diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml deleted file mode 100644 index c3b46af66a..0000000000 --- a/.github/workflows/run_tests.yml +++ /dev/null @@ -1,259 +0,0 @@ -name: "tidy3d-frontend-tests" - -on: - workflow_dispatch: - inputs: - remote_tests: - description: 'remote-tests' - type: boolean - default: true - local_tests: - description: 'local-tests' - type: boolean - default: false - push: - branches: [ develop, latest , 'pre/*'] - pull_request: - branches: - - latest - - develop - - 'pre/*' - types: ['opened', 'reopened', 'synchronize', 'ready_for_review'] - pull_request_review: - types: [submitted] - -jobs: - determine-test-scope: - runs-on: [ inhouse ] - if: | - github.event.pull_request.draft == false || - github.ref == 'refs/heads/develop' || - github.event_name == 'workflow_dispatch' - outputs: - local_tests: ${{ steps.determine-test-type.outputs.local_tests }} - remote_tests: ${{ steps.determine-test-type.outputs.remote_tests }} - steps: - - name: determine-test-type - id: determine-test-type - env: - DRAFT_STATE: ${{ github.event.pull_request.draft }} - EVENT_NAME: ${{ github.event_name }} - REVIEW_STATE: ${{ github.event.review.state }} - REF: ${{ github.ref }} - INPUT_LOCAL: ${{ github.event.inputs.local_tests }} - INPUT_REMOTE: ${{ github.event.inputs.remote_tests }} - run: | - echo "Event: $EVENT_NAME" - echo "Draft: $DRAFT_STATE" - echo "Review State: $REVIEW_STATE" - echo "Git REF: $REF" - echo "Input local: $INPUT_FAST" - echo "Input remote: $INPUT_FULL" - - remote_tests=false - local_tests=false - # Workflow_dispatch input override - if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then - - # Each option is self contained - if [[ "$INPUT_REMOTE" == "true" ]]; then - remote_tests=true - fi - - if [[ "$INPUT_LOCAL" == "true" ]]; then - local_tests=true - fi - fi - - # If triggered by PR review and approved - if [[ "$EVENT_NAME" == "pull_request_review" ]]; then - if [[ "$REVIEW_STATE" == "approved" ]]; then - local_tests=true - remote_tests=true - else - local_tests=false - remote_tests=false - fi - fi - - # All PRs that have been triggered need local tests - if [[ "$EVENT_NAME" == "pull_request" ]]; then - local_tests=true - fi - - # If it's a push to develop - if [[ "$EVENT_NAME" == "push" && "$REF" == "refs/heads/develop" ]]; then - local_tests=true - remote_tests=true - fi - - echo "local_tests=$local_tests" >> $GITHUB_OUTPUT - echo "remote_tests=$remote_tests" >> $GITHUB_OUTPUT - echo "local_tests=$local_tests" - echo "remote_tests=$remote_tests" - - lint: - needs: determine-test-scope - if: ( needs.determine-test-scope.outputs.local_tests == 'true' ) || ( needs.determine-test-scope.outputs.remote_tests == 'true' ) - name: Run linting - runs-on: [ inhouse ] - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - uses: astral-sh/ruff-action@v3 - with: - version: 0.5.5 - - name: Run ruff format - run: ruff format --check --diff - - name: Run ruff check - run: ruff check tidy3d - - local-tests: - # Run on open PRs OR when manually triggered with local_tests=true - needs: determine-test-scope - if: needs.determine-test-scope.outputs.local_tests == 'true' - name: Python ${{ matrix.python-version }} - self-hosted-runner - runs-on: [ inhouse ] - strategy: - matrix: - python-version: ['3.9', '3.13'] - defaults: - run: - shell: bash - env: # Set environment variables for the whole job - PIP_ONLY_BINARY: gdstk - MPLBACKEND: agg - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install project - run: | - python -m venv ${GITHUB_WORKSPACE}/.venv - source ${GITHUB_WORKSPACE}/.venv/bin/activate - python --version - which python - which pip - pip list - pip install --upgrade pip wheel setuptools - pip install gdstk --only-binary gdstk - pip install -e ".[dev]" - - - name: Run tests with coverage - env: - PYTHONUNBUFFERED: "1" - run: | - source ${GITHUB_WORKSPACE}/.venv/bin/activate - pytest --cov=tidy3d -rF --tb=short tests/_test_data/_test_datasets_no_vtk.py - pytest --cov=tidy3d -rF --tb=short tests - coverage report -m - TOTAL_COVERAGE=$(coverage report --format=total) - echo "total=$TOTAL_COVERAGE" >> "$GITHUB_ENV" - echo "### Total coverage: ${TOTAL_COVERAGE}%" - - remote-tests: - # Run tests on a push event OR a workflow dispatch with remote_tests - needs: determine-test-scope - if: needs.determine-test-scope.outputs.remote_tests == 'true' - name: Python ${{ matrix.python-version }} - ${{ matrix.platform }} - runs-on: ${{ matrix.platform }} - strategy: - matrix: - python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] - platform: [windows-latest, ubuntu-latest, macos-latest] - defaults: - run: - shell: bash - env: # Set environment variables for the whole job - PIP_ONLY_BINARY: gdstk - MPLBACKEND: agg - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 1 - - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - version: 2.1.1 - virtualenvs-create: true - virtualenvs-in-project: true - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install project - run: | - poetry --version - poetry env use python - poetry env info - poetry run pip install --upgrade pip wheel setuptools - poetry run pip install gdstk --only-binary gdstk - poetry install -E dev - - - name: Run doctests - run: | - poetry run pytest -rF --tb=short tidy3d - - - name: Run tests with coverage - env: - PYTHONUNBUFFERED: "1" - run: | - poetry run pytest --cov=tidy3d -rF --tb=short tests/_test_data/_test_datasets_no_vtk.py - poetry run pytest --cov=tidy3d -rF --tb=short tests - poetry run coverage report -m - TOTAL_COVERAGE=$(poetry run coverage report --format=total) - echo "total=$TOTAL_COVERAGE" >> "$GITHUB_ENV" - echo "### Total coverage: ${TOTAL_COVERAGE}%" - - - name: "Create badge" - if: ${{ github.ref == 'refs/heads/develop' }} - # https://gist.githubusercontent.com/nedbat/8c6980f77988a327348f9b02bbaf67f5 - uses: schneegans/dynamic-badges-action@v1.7.0 - with: - auth: ${{ secrets.GH_TIDY3D_COVERAGE_GIST }} - gistID: 4702549574741e87deaadba436218ebd - filename: tidy3d_extension.json - label: Coverage - message: ${{ env.total }}% - minColorRange: 60 - maxColorRange: 95 - valColorRange: ${{ env.total }} - style: "for-the-badge" - - pr-requirements-pass: - name: pr-requirements-pass - if: ( needs.determine-test-scope.outputs.local_tests == 'true' ) || ( needs.determine-test-scope.outputs.remote_tests == 'true' ) - needs: [local-tests, remote-tests, lint] - runs-on: [ inhouse ] - steps: - - name: check-passing-remote-tests - run: | - echo "Remote tests result: ${{ needs.remote-tests.result }}" - - if [[ "${{ needs.lint.result }}" != "success" ]]; then - echo "❌ Linting failed or was skipped." - exit 1 - fi - - if [[ "${{ needs.remote-tests.result }}" != "success" ]]; then - echo "❌ remote-tests failed or were skipped." - fi - - if [[ "${{ needs.local-tests.result }}" != "success" ]]; then - echo "❌ local-tests failed or were skipped." - exit 1 - fi - - echo "✅ All required test jobs passed!" diff --git a/.github/workflows/test_pr_latest_submodule.yaml b/.github/workflows/test_pr_latest_submodule.yaml deleted file mode 100644 index b40f3f4b10..0000000000 --- a/.github/workflows/test_pr_latest_submodule.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: "tidy3d-submodule-PR-tests" - -on: - workflow_dispatch: - push: - branches: [ latest ] - pull_request: - branches: - - latest - -jobs: - test-latest-submodules: - runs-on: ubuntu-latest - steps: - - name: Checkout repository with submodules - uses: actions/checkout@v4 - with: - submodules: 'recursive' - # This fetches only a single branch by default, so additional fetch is needed - fetch-depth: 0 # Optionally, set to 0 to fetch all history for all branches and tags - - - name: Initialize and update submodule - run: | - git submodule update --init --recursive - - - name: Check if submodules are up to date - shell: bash - run: | - NOTEBOOKS_PATH=docs/notebooks - FAQ_PATH=docs/faq - - # Checking out Notebooks submodule with the same branch as the main project - echo "Checking $NOTEBOOKS_PATH for updates..." - cd $NOTEBOOKS_PATH - NOTEBOOKS_CURRENT_COMMIT=$(git rev-parse HEAD) - echo $(git fetch --all --verbose) - echo $(git remote get-url origin) - if git show-ref --verify refs/remotes/origin/develop; then - echo "Branch develop exists." - else - echo "::error::Branch develop does not exist on remote." - exit 1 - fi - NOTEBOOKS_LATEST_COMMIT=$(git rev-parse refs/remotes/origin/develop) - echo "NOTEBOOKS_LATEST_COMMIT: $NOTEBOOKS_LATEST_COMMIT" - echo "NOTEBOOKS_CURRENT_COMMIT: $NOTEBOOKS_CURRENT_COMMIT" - - - cd ../.. - if [ "$NOTEBOOKS_LATEST_COMMIT" != "$NOTEBOOKS_CURRENT_COMMIT" ]; then - echo "::error ::Submodule $NOTEBOOKS_PATH is not up to date with the develop branch. Please update it." - exit 1 - else - echo "Submodule $NOTEBOOKS_PATH is up to date with the develop branch." - fi - - # Checking FAQs only on the develop branch. - echo "Checking $FAQ_PATH for updates..." - cd $FAQ_PATH - FAQ_CURRENT_COMMIT=$(git rev-parse HEAD) - echo $(git fetch --all --verbose) - echo $(git remote get-url origin) - FAQ_LATEST_COMMIT=$(git rev-parse refs/remotes/origin/develop) - echo "FAQ_LATEST_COMMIT: $FAQ_LATEST_COMMIT" - echo "FAQ_CURRENT_COMMIT: $FAQ_CURRENT_COMMIT" - cd ../.. - if [ "$FAQ_LATEST_COMMIT" != "$FAQ_CURRENT_COMMIT" ]; then - echo "::error ::Submodule $FAQ_PATH is not up to date. Please update it." - exit 1 - else - echo "Submodule $FAQ_PATH is up to date." - fi diff --git a/.github/workflows/sync-to-readthedocs-repo.yaml b/.github/workflows/tidy3d-docs-sync-readthedocs-repo.yml similarity index 98% rename from .github/workflows/sync-to-readthedocs-repo.yaml rename to .github/workflows/tidy3d-docs-sync-readthedocs-repo.yml index b0915c80b5..e5426d3136 100644 --- a/.github/workflows/sync-to-readthedocs-repo.yaml +++ b/.github/workflows/tidy3d-docs-sync-readthedocs-repo.yml @@ -1,4 +1,4 @@ -name: "sync-to-readthedocs-repo" +name: "docs/tidy3d/sync-to-readthedocs-repo" on: workflow_dispatch: diff --git a/.github/workflows/tidy3d-python-client-daily.yml b/.github/workflows/tidy3d-python-client-daily.yml new file mode 100644 index 0000000000..277b287c56 --- /dev/null +++ b/.github/workflows/tidy3d-python-client-daily.yml @@ -0,0 +1,23 @@ +name: public/tidy3d/python-client-daily-run + +on: + workflow_dispatch: + schedule: + - cron: '0 5 * * *' # Runs at 5am UTC + +permissions: + contents: write + pull-requests: write + +jobs: + update-lockfile: + uses: ./.github/workflows/tidy3d-python-client-update-lockfile.yml + with: + run-workflow: true + secrets: inherit + + submodule-tests: + uses: ./.github/workflows/tidy3d-python-client-submodules-test.yml + with: + run-workflow: true + secrets: inherit diff --git a/.github/workflows/test_develop_cli.yaml b/.github/workflows/tidy3d-python-client-develop-cli.yml similarity index 95% rename from .github/workflows/test_develop_cli.yaml rename to .github/workflows/tidy3d-python-client-develop-cli.yml index 2c410dd85a..07ee7f30fd 100644 --- a/.github/workflows/test_develop_cli.yaml +++ b/.github/workflows/tidy3d-python-client-develop-cli.yml @@ -1,4 +1,4 @@ -name: "test-develop-cli" +name: "public/tidy3d/python-client-develop-cli" on: workflow_dispatch: @@ -21,7 +21,8 @@ jobs: uses: actions/checkout@v4 with: ref: develop - + fetch-depth: 1 + submodules: false - name: Set up Python uses: actions/setup-python@v5 diff --git a/.github/workflows/release.yml b/.github/workflows/tidy3d-python-client-release.yml similarity index 98% rename from .github/workflows/release.yml rename to .github/workflows/tidy3d-python-client-release.yml index 15ff62060b..ed60f2004e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/tidy3d-python-client-release.yml @@ -1,4 +1,4 @@ -name: "tidy3d-release" +name: "public/tidy3d/python-client-release" permissions: contents: write diff --git a/.github/workflows/test_daily_latest_submodule.yaml b/.github/workflows/tidy3d-python-client-submodules-test.yml similarity index 75% rename from .github/workflows/test_daily_latest_submodule.yaml rename to .github/workflows/tidy3d-python-client-submodules-test.yml index e32ee31553..b53fc2ea74 100644 --- a/.github/workflows/test_daily_latest_submodule.yaml +++ b/.github/workflows/tidy3d-python-client-submodules-test.yml @@ -1,14 +1,31 @@ -name: "tidy3d-submodule-daily-tests" +name: "public/tidy3d/python-client-submodule-tests" on: + push: + branches: [ latest ] + + pull_request: + branches: + - latest + workflow_dispatch: - schedule: - - cron: '0 9 * * *' # Runs at 9am UK-time every day + inputs: + run-workflow: + required: true + type: boolean + default: true + workflow_call: + inputs: + run-workflow: + required: true + type: boolean + default: true jobs: test-latest-submodules: runs-on: ubuntu-latest + if: github.event.inputs.run-workflow || inputs.run-workflow steps: - name: Checkout repository with submodules uses: actions/checkout@v4 @@ -21,30 +38,6 @@ jobs: run: | git submodule update --init --recursive - - name: Determine the latest pre/2.* branch - id: get_latest_pre_branch - run: | - # Fetch all branches - git fetch --all --quiet - - # List all remote branches for debugging purposes - echo "Available branches:" - git branch -r - - # List branches matching the pre/2.* pattern - BRANCHES=$(git branch -r | grep 'origin/pre/2\.' | sed 's|origin/||' | sort -V) - - # Debugging: Print out the matched branches - echo "Matched branches with pre/2.* pattern:" - echo "$BRANCHES" - - # Identify the latest branch - LATEST_BRANCH=$(echo "$BRANCHES" | tail -n 1) - - # Set the latest branch as an environment variable - echo "LATEST_BRANCH=$LATEST_BRANCH" >> $GITHUB_ENV - echo "Latest pre/2.* branch is: $LATEST_BRANCH" - - name: Check submodules for multiple branches shell: bash run: | @@ -104,4 +97,4 @@ jobs: echo "Submodule $FAQ_PATH is up to date." fi fi - done \ No newline at end of file + done diff --git a/.github/workflows/tidy3d-python-client-tests.yml b/.github/workflows/tidy3d-python-client-tests.yml new file mode 100644 index 0000000000..df7837ccc7 --- /dev/null +++ b/.github/workflows/tidy3d-python-client-tests.yml @@ -0,0 +1,465 @@ +name: "public/tidy3d/python-client-tests" + +on: + merge_group: + workflow_dispatch: + inputs: + remote_tests: + description: 'remote-tests' + type: boolean + default: true + local_tests: + description: 'local-tests' + type: boolean + default: false + pull_request: + branches: + - latest + - develop + - 'pre/*' + types: ['opened', 'reopened', 'synchronize', 'ready_for_review'] + pull_request_review: + types: [submitted] + +permissions: + contents: read + pull-requests: write + +jobs: + determine-test-scope: + runs-on: ubuntu-latest + if: | + github.event.pull_request.draft == false || + github.ref == 'refs/heads/develop' || + github.event_name == 'workflow_dispatch' + outputs: + local_tests: ${{ steps.determine-test-type.outputs.local_tests }} + remote_tests: ${{ steps.determine-test-type.outputs.remote_tests }} + pr_approval_state: ${{ steps.approval.outputs.approved }} + steps: + - name: check-current-approval-status + id: approval + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const {owner, repo} = context.repo + const number = context.payload.pull_request.number + const reviews = await github.rest.pulls.listReviews({owner, repo, pull_number: number}) + + const latestByUser = {} + reviews.data.forEach(r => latestByUser[r.user.id] = r) + + const approved = Object.values(latestByUser) + .some(r => r.state === 'APPROVED') + core.setOutput('approved', approved ? 'true' : 'false') + - name: determine-test-type + id: determine-test-type + env: + DRAFT_STATE: ${{ github.event.pull_request.draft }} + EVENT_NAME: ${{ github.event_name }} + REVIEW_STATE: ${{ github.event.review.state }} + REF: ${{ github.ref }} + INPUT_LOCAL: ${{ github.event.inputs.local_tests }} + INPUT_REMOTE: ${{ github.event.inputs.remote_tests }} + APPROVED: ${{ steps.approval.outputs.approved }} + run: | + echo "Event: $EVENT_NAME" + echo "Draft: $DRAFT_STATE" + echo "Review State: $REVIEW_STATE" + echo "Git REF: $REF" + echo "Input local: $INPUT_FAST" + echo "Input remote: $INPUT_FULL" + echo "Approved: $APPROVED" + + remote_tests=false + local_tests=false + # Workflow_dispatch input override + if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then + + # Each option is self contained + if [[ "$INPUT_REMOTE" == "true" ]]; then + remote_tests=true + fi + + if [[ "$INPUT_LOCAL" == "true" ]]; then + local_tests=true + fi + fi + + # All PRs that have been triggered need local tests and approved ones need to re-run the remote tests + if [[ "$EVENT_NAME" == "pull_request" ]]; then + local_tests=true + [[ "$APPROVED" == "true" ]] && remote_tests=true + fi + + if [[ "$EVENT_NAME" == "merge_group" ]]; then + local_tests=true + remote_tests=true + fi + + # If triggered by PR review and approved + if [[ "$EVENT_NAME" == "pull_request_review" ]]; then + if [[ "$REVIEW_STATE" == "approved" ]]; then + local_tests=true + remote_tests=true + else + local_tests=false + remote_tests=false + fi + fi + + # If it's a push to develop + if [[ "$EVENT_NAME" == "push" && "$REF" == "refs/heads/develop" ]]; then + local_tests=true + remote_tests=true + fi + + echo "local_tests=$local_tests" >> $GITHUB_OUTPUT + echo "remote_tests=$remote_tests" >> $GITHUB_OUTPUT + echo "local_tests=$local_tests" + echo "remote_tests=$remote_tests" + + lint: + needs: determine-test-scope + if: ( needs.determine-test-scope.outputs.local_tests == 'true' ) || ( needs.determine-test-scope.outputs.remote_tests == 'true' ) + name: verify-linting + runs-on: ubuntu-latest + container: ghcr.io/astral-sh/uv:debian + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: false + - uses: astral-sh/ruff-action@v3 + with: + version: 0.11.11 + - name: Run ruff format + run: ruff format --check --diff + - name: Run ruff check + run: ruff check tidy3d + + verify-schema-change: + name: verify-schema-change + needs: determine-test-scope + if: | + (( needs.determine-test-scope.outputs.local_tests == 'true' ) || + ( needs.determine-test-scope.outputs.remote_tests == 'true' )) + runs-on: ubuntu-latest + container: ghcr.io/astral-sh/uv:debian + defaults: + run: + shell: bash + steps: + - name: checkout-branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: '0' + + - name: git-config + run: | + cd $GITHUB_WORKSPACE + git config --global --add safe.directory $GITHUB_WORKSPACE + + - name: install-depedencies + run: | + uv venv $GITHUB_WORKSPACE/.venv -p 3.11 + source $GITHUB_WORKSPACE/.venv/bin/activate + uv pip install -e "$GITHUB_WORKSPACE" + + - name: get-tidy3d-version + id: get-version + run: | + source $GITHUB_WORKSPACE/.venv/bin/activate + version=$(python -c "import tidy3d; print(tidy3d.__version__)") + echo "tidy3d version is $version" + echo "version=$version" >> $GITHUB_OUTPUT + + - name: verify-committed-schema + run: | + echo "Regenerating schema to check if committed files are up-to-date..." + source $GITHUB_WORKSPACE/.venv/bin/activate + python $GITHUB_WORKSPACE/scripts/regenerate_schema.py + + cd $GITHUB_WORKSPACE + echo "Checking for differences with HEAD commit..." + git status + git log + git diff HEAD --name-status --exit-code -- $GITHUB_WORKSPACE/schemas + echo "✅ Committed schema is up-to-date." + + - name: run-schema-diff + id: schema-diff + run: | + set -e + # Use git diff to compare the two directories and get a list of changes + # The command exits with 0 if no changes, 1 if changes are found. + # We use '|| true' to prevent the workflow from stopping here on failure. + cd $GITHUB_WORKSPACE + diff_output=$(git diff origin/develop --name-status -- $GITHUB_WORKSPACE/schemas || true) + + # Check if there are any changes + if [ -z "$diff_output" ]; then + echo "✅ Schemas are up-to-date." + echo "changed=false" >> $GITHUB_OUTPUT + exit 0 + fi + + # If there are changes, create a Markdown table + echo "❌ Schema has changed compared to develop! Please regenerate and commit the changes." + echo "changed=true" >> $GITHUB_OUTPUT + + # Write the report to the GitHub Step Summary + echo "### Schema Change Summary" >> $GITHUB_STEP_SUMMARY + echo "| Status | File |" >> $GITHUB_STEP_SUMMARY + echo "|:---:|:---|" >> $GITHUB_STEP_SUMMARY + + echo "$diff_output" | while read -r line; do + status_code=$(echo "$line" | cut -f1) + file_path=$(echo "$line" | cut -f2 | sed 's#tidy3d/schemas/##') # Clean up path + + case $status_code in + "A") status="Added 🟢";; + "M") status="Modified 🟡";; + "D") status="Removed 🔴";; + *) status="Unknown";; + esac + + echo "| $status | \`$file_path\` |" >> $GITHUB_STEP_SUMMARY + done + + - name: verify-allowed-changes + if: steps.schema-diff.outputs.changed == 'true' + run: | + set -e + version="${{ steps.get-version.outputs.version }}" + if [[ "$version" == *rc* ]]; then + echo "✅ Passing: Schema changed on a release candidate version ($version), which is permitted." + else + echo "❌ Failing: Schema changed on a non-rc release version ($version)." + exit 1 + fi + + local-tests: + # Run on open PRs OR when manually triggered with local_tests=true + needs: determine-test-scope + if: needs.determine-test-scope.outputs.local_tests == 'true' + name: python-${{ matrix.python-version }}-self-hosted-runner + runs-on: [ slurm-runner, 4xcpu ] + container: + image: ghcr.io/astral-sh/uv:debian + options: --user 31001:61001 # Required slurm-batch UID: slurm GID for tmp/ file removal + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name }}-${{ matrix.python-version }}-local + cancel-in-progress: true + strategy: + matrix: + python-version: ['3.9', '3.13'] + defaults: + run: + shell: bash + env: # Set environment variables for the whole job + PIP_ONLY_BINARY: gdstk + MPLBACKEND: agg + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required 0 for diff report. + submodules: false + + - name: install-project + env: + PYTHON_VERSION: ${{ matrix.python-version }} + run: | + if [ -f /.dockerenv ]; then + echo "Running inside a Docker container (detected via /.dockerenv)" + else + echo "Not running inside a Docker container (/.dockerenv not found)" + fi + uv venv -p $PYTHON_VERSION ${GITHUB_WORKSPACE}/.venv + source ${GITHUB_WORKSPACE}/.venv/bin/activate + which python + which uv + python --version + uv pip list + uv pip install gdstk --only-binary gdstk + uv pip install -e ".[dev]" + + echo "Testing vtk is correctly installed." + python -c "import vtk" + + - name: run-tests-coverage + env: + PYTHONUNBUFFERED: "1" + run: | + source ${GITHUB_WORKSPACE}/.venv/bin/activate + # pytest --cov=tidy3d -rF --tb=short tests/_test_data/_test_datasets_no_vtk.py + pytest --cov=tidy3d -rF --tb=short tests + coverage report -m + coverage xml -o ${GITHUB_WORKSPACE}/coverage.xml + TOTAL_COVERAGE=$(coverage report --format=total) + echo "total=$TOTAL_COVERAGE" >> "$GITHUB_ENV" + echo "### Total coverage: ${TOTAL_COVERAGE}%" + + - name: diff-coverage-report + if: >- + matrix.python-version == '3.13' && + github.event_name == 'pull_request' && + !contains(github.event.pull_request.labels.*.name, 'ignore_diff_coverage') + run: | + source ${GITHUB_WORKSPACE}/.venv/bin/activate + git config --global --add safe.directory ${GITHUB_WORKSPACE} + diff-cover ${GITHUB_WORKSPACE}/coverage.xml \ + --compare-branch origin/${{ github.event.pull_request.base.ref }} \ + --format markdown:diff-coverage.md + + - uses: actions/github-script@v7 + if: >- + matrix.python-version == '3.13' && + github.event_name == 'pull_request' && + !contains(github.event.pull_request.labels.*.name, 'ignore_diff_coverage') && + github.event.pull_request.head.repo.fork == false + with: + result-encoding: string + script: | + const fs = require('fs'); + const marker = ''; + const body = fs.readFileSync('diff-coverage.md','utf8'); + const report = `${marker}\n${body}`; + const {data:comments}=await github.rest.issues.listComments({ + owner:context.repo.owner, + repo:context.repo.repo, + issue_number:context.issue.number, + }); + const existing = comments.find(c=>c.body.startsWith(marker)); + if(existing) { + await github.rest.issues.updateComment({ + owner:context.repo.owner, + repo:context.repo.repo, + comment_id:existing.id, + body:report, + }); + } else { + await github.rest.issues.createComment({ + owner:context.repo.owner, + repo:context.repo.repo, + issue_number:context.issue.number, + body:report, + }); + } + + remote-tests: + # Run tests on a push event OR a workflow dispatch with remote_tests + needs: determine-test-scope + if: needs.determine-test-scope.outputs.remote_tests == 'true' + name: python-${{ matrix.python-version }}-${{ matrix.platform }} + runs-on: ${{ matrix.platform }} + permissions: + contents: read + pull-requests: write + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ github.event_name }}-${{ matrix.platform }}-${{ matrix.python-version }}-remote + cancel-in-progress: true + strategy: + matrix: + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13'] + platform: [windows-latest, ubuntu-latest, macos-latest] + defaults: + run: + shell: bash + env: # Set environment variables for the whole job + PIP_ONLY_BINARY: gdstk + MPLBACKEND: agg + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: false + + - name: install-poetry + uses: snok/install-poetry@v1 + with: + version: 2.1.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: set-python-${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: install-project + run: | + poetry --version + poetry env use python + poetry env info + poetry run pip install --upgrade pip wheel setuptools + poetry run pip install gdstk --only-binary gdstk + poetry install -E dev + + - name: run-doctests + run: | + poetry run pytest -rF --tb=short tidy3d + + - name: run-tests-coverage + env: + PYTHONUNBUFFERED: "1" + run: | + poetry run pytest --cov=tidy3d -rF --tb=short tests/_test_data/_test_datasets_no_vtk.py + poetry run pytest --cov=tidy3d -rF --tb=short tests + poetry run coverage report -m + TOTAL_COVERAGE=$(poetry run coverage report --format=total) + echo "total=$TOTAL_COVERAGE" >> "$GITHUB_ENV" + echo "### Total coverage: ${TOTAL_COVERAGE}%" + + - name: create-badge + if: ${{ github.ref == 'refs/heads/develop' }} + # https://gist.githubusercontent.com/nedbat/8c6980f77988a327348f9b02bbaf67f5 + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{ secrets.GH_TIDY3D_COVERAGE_GIST }} + gistID: 4702549574741e87deaadba436218ebd + filename: tidy3d_extension.json + label: Coverage + message: ${{ env.total }}% + minColorRange: 60 + maxColorRange: 95 + valColorRange: ${{ env.total }} + style: "for-the-badge" + + pr-requirements-pass: + name: pr-requirements-pass + if: | + always() && + ((github.event_name == 'pull_request') || (github.event_name == 'pull_request_review')) && + (( needs.determine-test-scope.outputs.pr_approval_state == 'true' ) && + ( needs.determine-test-scope.outputs.local_tests == 'true' ) || + ( needs.determine-test-scope.outputs.remote_tests == 'true' )) + needs: [local-tests, remote-tests, lint, verify-schema-change] + runs-on: ubuntu-latest + steps: + - name: check-passing-remote-tests + run: | + echo "Local tests result: ${{ needs.local-tests.result }}" + echo "Remote tests result: ${{ needs.remote-tests.result }}" + + if [[ "${{ needs.lint.result }}" != 'success' ]]; then + echo "❌ Linting failed or was skipped." + exit 1 + elif [[ "${{ needs.verify-schema-change.result }}" != 'success' ]]; then + echo "❌ verify-schema-change failed or was skipped." + exit 1 + elif [[ "${{ needs.remote-tests.result }}" != 'success' ]]; then + echo "❌ remote-tests failed or were skipped." + exit 1 # Given remote-tests always run after a PR is approved + elif [[ "${{ needs.local-tests.result }}" != 'success' ]]; then + echo "❌ local-tests failed or were skipped." + elif [[ "${{ needs.determine-test-scope.outputs.pr_approval_state }}" == 'true' && github.event.pull_request ]]; then + echo "❌ PR requires approval." + exit 1 + fi + echo "✅ All required test jobs passed!" diff --git a/.github/workflows/tidy3d-python-client-update-lockfile.yml b/.github/workflows/tidy3d-python-client-update-lockfile.yml new file mode 100644 index 0000000000..718c29136f --- /dev/null +++ b/.github/workflows/tidy3d-python-client-update-lockfile.yml @@ -0,0 +1,63 @@ +name: public/tidy3d/python-client-update-lockfile + +on: + workflow_dispatch: + inputs: + run-workflow: + description: 'Set to true to update the lock file and create a PR' + required: true + type: boolean + default: true + + workflow_call: + inputs: + run-workflow: + description: 'Set to true to update the lock file and create a PR' + required: true + type: boolean + default: true + +jobs: + update-lockfile: + if: github.event.inputs.run-workflow || inputs.run-workflow + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: false + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.9' + + - name: Install Poetry + uses: snok/install-poetry@v1 + with: + version: 2.1.1 + virtualenvs-create: true + virtualenvs-in-project: true + + - name: Update lock file + run: | + set -e + poetry update --lock + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(deps): :robot: Daily update `poetry.lock`" + title: "chore(deps): :robot: Daily update `poetry.lock`" + body: | + This pull request was automatically generated by a GitHub Action. + + It updates the `poetry.lock` file to reflect changes in the pip state, and whether the package is broken by external dependency changes. + branch: "daily-chore/update-poetry-lock" + base: "develop" + delete-branch: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8440b0412a..928cb133da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,8 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.5.5" + rev: "v0.11.11" hooks: - - id: ruff + - id: ruff-check args: [ --fix ] - id: ruff-format + diff --git a/CHANGELOG.md b/CHANGELOG.md index 856e48f034..2fca4ca471 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,90 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.9.0rc2] - 2025-07-17 + +### Added +- Implemented `FreqRange` utility class for frequency/wavelength handling with constructor methods `from_freq_interval()`, `from_wavelength()`, and `from_wvl_interval()`. +- Add support for `np.unwrap` in `tidy3d.plugins.autograd`. +- Add Nunley variant to germanium material library based on Nunley et al. 2016 data. +- Add `PointDipole.sources_from_angles()` that constructs a list of `PointDipole` objects needed to emulate a dipole oriented at a user-provided set of polar and azimuthal angles. +- Added `priority` parameter to `web.run()` and related functions to allow vGPU users to set task priority (1-10) in the queue. +- `EMEFieldMonitor` now supports `interval_space`. +- `Simulation.precision` option allows to select `"double"` precision for very high-accuracy results. Note that this is very rarely needed, and doubles the simulation computational weight and correspondingly FlexCredit cost. +- Added material type `PMCMedium` for perfect magnetic conductor. +- `ModeSimulation.plot()` method that plots the mode simulation plane by default, or the containing FDTD simulation if any of ``x``, ``y``, or ``z`` is passed. +- Enable singularity correction at PEC and lossy metal edges. +- New `VolumeMesher` simulation type and associated `VolumeMeshMonitor` and `VolumeMesherData`, which can be used to run the unstructured meshing for a `HeatChargeSimulation` separately before running the solver. + +### Changed +- Switched to an analytical gradient calculation for spatially-varying pole-residue models (`CustomPoleResidue`). +- `GaussianBeam` and `AstigmaticGaussianBeam` default `num_freqs` reset to 1 (it was set to 3 in v2.8.0) and a warning is issued for a broadband, angled beam for which `num_freqs` may not be sufficiently large. +- Set the maximum `num_freqs` to 20 for all broadband sources (we have been warning about the introduction of this hard limit for a while). +- Significantly improved performance of the `tidy3d.plugins.autograd.grey_dilation` morphological operation and its gradient calculation. The new implementation is orders of magnitude faster, especially for large arrays and kernel sizes. +- Warnings are now generated (instead of errors) when instantiating `PML`, `StablePML`, +or `Absorber` classes (or when invoking `pml()`, `stable_pml()`, or `absorber()` functions) +with fewer layers than recommended. +- Warnings and error messages originating from `Structure`, `Source`, or `Monitor` classes now refer to problematic objects by their user-supplied `name` attribute, alongside their index. +- File downloads are atomic. Interruptions or failures during download will no longer result in incomplete files. +- Warnings are now generated (instead of errors) when instantiating `PML`, `StablePML`, or `Absorber` classes (or when invoking `pml()`, `stable_pml()`, or `absorber()` functions) with fewer layers than recommended. +- `Simulation.subsection` can no longer take `symmetry` as an argument - the symmetry is always taken from the original simulation. +- If a mode simulation is crossing a symmetry plane of the larger simulation domain, but the mode plane is not symmetric, a warning is issued that it will be expanded symmetrically. Previously this warning only happened during the solver run. +- Enhanced `PolySlab` and `Cylinder` gradient computation via adaptive field sampling along geometry boundaries instead of fixed-grid center sampling. +- Shape derivatives have been sped up significantly, especially for simulations containing many structures in a `GeometryGroup`. + +### Fixed +- Arrow lengths are now scaled consistently in the X and Y directions, and their lengths no longer exceed the height of the plot window. +- Bug in `PlaneWave` defined with a negative `angle_theta` which would lead to wrong injection. +- Plots of objects defined by shape intersection logic will no longer display thin line artifacts. +- Fixed incorrect gradient computation in PyTorch plugin (`to_torch`) for functions returning multi-element arrays. +- `MonitorData.get_amplitude()` no longers multiplies by a factor of `1j` and now directly returns the complex value of the data. +- `EMESimulationData.port_modes_tuple` is now symmetry-expanded. +- Fixed `Medium2D` validation error message when invalid data is passed to `ss`. +- The phase of the amplitudes of a `DiffractionMonitor` was correctly centered such that the origin is at the monitor center. + +## [2.9.0rc1] - 2025-06-10 + +### Added + +- Fields `convex_resolution`, `concave_resolution`, and `mixed_resolution` in `CornerFinderSpec` can be used to take into account the dimensions of autodetected convex, concave, or mixed geometric features when `dl_min` is automatically inferred during automatic grid generation. +- `LayerRefinementSpec` now supports automatic thin gap meshing through fields `gap_meshing_iters` and `dl_min_from_gap_width`. +- Added `eps_lim` keyword argument to `Simulation.plot_eps()` for manual control over the permittivity color limits. +- Added `thickness` parameter to `LossyMetalMedium` for computing surface impedance of a thin conductor. +- `priority` field in `Structure` and `MeshOverrideStructure` for setting the behavior in structure overlapping region. When its value is `None`, the priority is automatically determined based on the material property and simulation's `structure_priority_mode`. +- Automatically apply `matplotlib` styles when importing `tidy3d` which can be reverted via the `td.restore_matplotlib_rcparams()` function. +- Added `TriangleMesh.from_height_expression` class method to create a mesh from an analytical height function defined on a 2D grid and `TriangleMesh.from_height_grid` class method to create a mesh from height values sampled on a 2D grid. +- Added heat sources with custom spatial dependence. It is now possible to add a `SpatialDataArray` as the `rate` in a `HeatSource`. +- Added Transient Heat simulations. It is now possible to run transient Heat simulations. This can be done by specifying `analysis_spec` of `HeatChargeSimulation` object as `UnsteadyHeatAnalysis`. +- A `num_grid_cells` field to `WavePort`, which ensures that there are 5 grid cells across the port. Grid refinement can be disabled by passing `None` to `num_grid_cells`. + +### Fixed +- Fixed bug in broadband adjoint source creation when forward simulation had a pulse amplitude greater than 1 or a nonzero pulse phase. +- Fixed shaping of `CustomMedium` gradients when permittivity data includes a frequency dimension with multiple entries. +- Bug in contains check for `LumpedElement`, which should allow the case of a `LumpedElement` touching the simulation boundaries. +- Bug when generating a grid with snapping points near the simulation boundaries. +- Fixed field colocation in `EMEModeSolverMonitor`. +- Solver error for EME simulations with bends, introduced when support for 2D EME simulations was added. +- Internal interpolation errors with some versions of `xarray` and `numpy`. +- If `ModeSpec.angle_rotation=True` for a mode object, validate that the structure rotation can be successfully done. Also, error if the medium cannot be rotated (e.g. anisotropic or custom medium), which would previously have just produced wrong results. +- Characteristic impedance calculations in the `ImpedanceCalculator` using definitions that rely on flux, which were giving incorrect results for lossy transmission lines. +- Fixed handling of symmetry when creating adjoint field sources and added warning when broken up adjoint simulations do not have the same symmetry as the forward simulation. +- Validation for `CustomGridBoundaries`, which was previously allowing unsorted arrays and arrays with less than two entries. +- `DiffractionMonitor` results to apply finite grid field corrections for higher precision when comparing e.g. to `FluxMonitor` computations of total power. +- Bug when validating the grid resolution near `CoaxialLumpedPort`. + +### Changed +- Relaxed bounds checking of path integrals during `WavePort` validation. +- Internal adjoint helper methods are now prefixed with an underscore to separate them from the public API. +- Drop the dependency on `gdspy`, which has been unmaintained for over two years. Interfaces previously relying on `gdspy` now use its maintained successor, `gdstk`, with equivalent functionality. +- Small (around 1e-4) numerical precision improvements in EME solver. +- Adjoint source frequency width is adjusted to decay sufficiently before zero frequency when possible to improve accuracy of simulation normalization when using custom current sources. +- Change `VisualizationSpec` validator for checking validity of user specified colors to only issue a warning if matplotlib is not installed instead of an error. +- Improved performance of `tidy3d.web.delete_old()` for large folders. +- Upon initialization, an FDTD `Simulation` will now try to create all `ModeSolver` objects associated to `ModeSource`-s and `ModeMonitor`-s so they can be validated. +- `tidy3d.plugins.autograd.interpolate_spline()` and `tidy3d.plugins.autograd.add_at()` can now be called with keyword arguments during tracing. +- Zero-size dimensions automatically receive periodic boundary conditions instead of raising an error. +- Set `ModeSpec` precision to `double` by default for more accurate mode solver results. Does not apply to `EMEModeSpec`, where the `auto` precision is still default for speed and cost. + ## [2.8.4] - 2025-05-15 ### Added @@ -50,8 +134,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed `reverse` property of `td.Scene.plot_structures_property()` to also reverse the colorbar. - -### Fixed - Fixed bug in surface gradient computation where fields, instead of gradients, were being summed in frequency. ## [2.8.2] - 2025-04-09 @@ -1618,7 +1700,8 @@ which fields are to be projected is now determined automatically based on the me - Job and Batch classes for better simulation handling (eventually to fully replace webapi functions). - A large number of small improvements and bug fixes. -[Unreleased]: https://github.com/flexcompute/tidy3d/compare/v2.8.4...develop +[Unreleased]: https://github.com/flexcompute/tidy3d/compare/v2.9.0rc1...develop +[2.9.0rc1]: https://github.com/flexcompute/tidy3d/compare/v2.8.4...v2.9.0rc1 [2.8.4]: https://github.com/flexcompute/tidy3d/compare/v2.8.3...v2.8.4 [2.8.3]: https://github.com/flexcompute/tidy3d/compare/v2.8.2...v2.8.3 [2.8.2]: https://github.com/flexcompute/tidy3d/compare/v2.8.1...v2.8.2 diff --git a/docs/_ext/custom-meta.py b/docs/_ext/custom-meta.py index ef4a70a614..1f5a9f9ef0 100644 --- a/docs/_ext/custom-meta.py +++ b/docs/_ext/custom-meta.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os diff --git a/docs/_ext/custom-robots.py b/docs/_ext/custom-robots.py index f796a6e509..c0a0002294 100644 --- a/docs/_ext/custom-robots.py +++ b/docs/_ext/custom-robots.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os diff --git a/docs/_ext/custom-sitemap.py b/docs/_ext/custom-sitemap.py index aec6a5d5cb..3af404160e 100644 --- a/docs/_ext/custom-sitemap.py +++ b/docs/_ext/custom-sitemap.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import xml.etree.ElementTree as ET diff --git a/docs/api/charge/discretization.rst b/docs/api/charge/discretization.rst deleted file mode 100644 index aa2ee5cce7..0000000000 --- a/docs/api/charge/discretization.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. currentmodule:: tidy3d - -Grid Specification --------------------- - -.. autosummary:: - :toctree: ../_autosummary/ - :template: module.rst - - tidy3d.UniformUnstructuredGrid - tidy3d.DistanceUnstructuredGrid diff --git a/docs/api/charge/mediums.rst b/docs/api/charge/mediums.rst index 3bc6d7ea1f..422bf5676f 100644 --- a/docs/api/charge/mediums.rst +++ b/docs/api/charge/mediums.rst @@ -18,6 +18,7 @@ Mobility :toctree: ../_autosummary/ :template: module.rst + tidy3d.ConstantMobilityModel tidy3d.CaugheyThomasMobility diff --git a/docs/api/charge/output_data.rst b/docs/api/charge/output_data.rst index 3b08dd66b2..f14a60d951 100644 --- a/docs/api/charge/output_data.rst +++ b/docs/api/charge/output_data.rst @@ -26,25 +26,3 @@ Monitor Data tidy3d.SteadyFreeCarrierData tidy3d.SteadyCapacitanceData - -Unstructured Data Classes -^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. autosummary:: - :toctree: ../_autosummary/ - :template: module.rst - - tidy3d.TriangularGridDataset - tidy3d.TetrahedralGridDataset - - -Individual Datasets -^^^^^^^^^^^^^^^^^^^ - -.. autosummary:: - :toctree: ../_autosummary/ - :template: module.rst - - tidy3d.PointDataArray - tidy3d.CellDataArray - tidy3d.IndexedDataArray diff --git a/docs/api/heat/analysis.rst b/docs/api/heat/analysis.rst new file mode 100644 index 0000000000..58f7e49aa4 --- /dev/null +++ b/docs/api/heat/analysis.rst @@ -0,0 +1,11 @@ +.. currentmodule:: tidy3d + +Transient Heat Analysis +----------------- + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.UnsteadySpec + tidy3d.UnsteadyHeatAnalysis \ No newline at end of file diff --git a/docs/api/heat/output_data.rst b/docs/api/heat/output_data.rst index 235cde7dc3..c1d38d1624 100644 --- a/docs/api/heat/output_data.rst +++ b/docs/api/heat/output_data.rst @@ -23,26 +23,3 @@ Monitor Data :template: module.rst tidy3d.TemperatureData - - -Unstructured Data Classes -^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. autosummary:: - :toctree: ../_autosummary/ - :template: module.rst - - tidy3d.TriangularGridDataset - tidy3d.TetrahedralGridDataset - - -Individual Datasets -^^^^^^^^^^^^^^^^^^^ - -.. autosummary:: - :toctree: ../_autosummary/ - :template: module.rst - - tidy3d.PointDataArray - tidy3d.CellDataArray - tidy3d.IndexedDataArray diff --git a/docs/api/index.rst b/docs/api/index.rst index 9001b0574c..591c2ebfdb 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -24,6 +24,7 @@ API |:computer:| scene logging submit_simulations + mesh/index heat/index charge/index eme/index @@ -33,6 +34,7 @@ API |:computer:| constants abstract_base abstract_models + viz .. include:: /api/simulation.rst .. include:: /api/boundary_conditions.rst @@ -51,6 +53,7 @@ API |:computer:| .. include:: /api/scene.rst .. include:: /api/logging.rst .. include:: /api/submit_simulations.rst +.. include:: /api/mesh/index.rst .. include:: /api/heat/index.rst .. include:: /api/charge/index.rst .. include:: /api/eme/index.rst @@ -58,4 +61,5 @@ API |:computer:| .. include:: /api/plugins/index.rst .. include:: /api/constants.rst .. include:: /api/abstract_base.rst -.. include:: /api/abstract_models.rst \ No newline at end of file +.. include:: /api/abstract_models.rst +.. include:: /api/viz.rst \ No newline at end of file diff --git a/docs/api/mediums.rst b/docs/api/mediums.rst index bb3ba9b7b1..12b4169e82 100644 --- a/docs/api/mediums.rst +++ b/docs/api/mediums.rst @@ -16,6 +16,7 @@ Spatially uniform tidy3d.Medium tidy3d.LossyMetalMedium tidy3d.PECMedium + tidy3d.PMCMedium tidy3d.FullyAnisotropicMedium Spatially varying @@ -75,6 +76,7 @@ Medium Perturbations tidy3d.PerturbationMedium tidy3d.PerturbationPoleResidue tidy3d.NedeljkovicSorefMashanovich + tidy3d.ParameterPerturbation General Mediums (can be both dispersive and non-dispersive) diff --git a/docs/api/heat/discretization.rst b/docs/api/mesh/discretization.rst similarity index 100% rename from docs/api/heat/discretization.rst rename to docs/api/mesh/discretization.rst diff --git a/docs/api/mesh/index.rst b/docs/api/mesh/index.rst new file mode 100644 index 0000000000..837c10b3a5 --- /dev/null +++ b/docs/api/mesh/index.rst @@ -0,0 +1,15 @@ +Unstructured mesh |:spider_web:| +================================= + +.. toctree:: + :hidden: + + discretization + mesher + monitor + output_data + +.. include:: /api/mesh/discretization.rst +.. include:: /api/mesh/mesher.rst +.. include:: /api/mesh/monitor.rst +.. include:: /api/mesh/output_data.rst diff --git a/docs/api/mesh/mesher.rst b/docs/api/mesh/mesher.rst new file mode 100644 index 0000000000..d28d8a96eb --- /dev/null +++ b/docs/api/mesh/mesher.rst @@ -0,0 +1,10 @@ +.. currentmodule:: tidy3d + +Volume mesher +-------------- + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.VolumeMesher diff --git a/docs/api/mesh/monitor.rst b/docs/api/mesh/monitor.rst new file mode 100644 index 0000000000..7bf92b73d6 --- /dev/null +++ b/docs/api/mesh/monitor.rst @@ -0,0 +1,10 @@ +.. currentmodule:: tidy3d + +Mesh monitors +-------------- + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.VolumeMeshMonitor diff --git a/docs/api/mesh/output_data.rst b/docs/api/mesh/output_data.rst new file mode 100644 index 0000000000..da1e265966 --- /dev/null +++ b/docs/api/mesh/output_data.rst @@ -0,0 +1,47 @@ +.. currentmodule:: tidy3d + +Output Data +------------- + + +Simulation Data +^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.VolumeMesherData + + +Monitor Data +^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.VolumeMeshData + + +Unstructured Data Classes +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.TriangularGridDataset + tidy3d.TetrahedralGridDataset + + +Individual Datasets +^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.PointDataArray + tidy3d.CellDataArray + tidy3d.IndexedDataArray diff --git a/docs/api/monitors.rst b/docs/api/monitors.rst index 861351d980..fc19e7456b 100644 --- a/docs/api/monitors.rst +++ b/docs/api/monitors.rst @@ -23,6 +23,7 @@ Monitor Types tidy3d.FieldProjectionKSpaceMonitor tidy3d.DiffractionMonitor tidy3d.DirectivityMonitor + tidy3d.AuxFieldTimeMonitor Apodization Specification ------------------------- diff --git a/docs/api/output_data.rst b/docs/api/output_data.rst index dfe025682a..877bb37d38 100644 --- a/docs/api/output_data.rst +++ b/docs/api/output_data.rst @@ -31,6 +31,7 @@ Collections of Data from single monitor tidy3d.FieldProjectionKSpaceData tidy3d.DiffractionData tidy3d.DirectivityData + tidy3d.AuxFieldTimeData Individual Datasets ------------------- diff --git a/docs/api/plugins/autograd.rst b/docs/api/plugins/autograd.rst index 1fdb5bc2ba..7e5a7997bc 100644 --- a/docs/api/plugins/autograd.rst +++ b/docs/api/plugins/autograd.rst @@ -7,28 +7,74 @@ Automatic Differentiation with Autograd ./../../../tidy3d/plugins/autograd/README +Differential Operators +~~~~~~~~~~~~~~~~~~~~~~ + .. autosummary:: :toctree: ../_autosummary/ :template: module.rst - tidy3d.plugins.autograd.functions.threshold - tidy3d.plugins.autograd.functions.rescale - tidy3d.plugins.autograd.functions.morphological_gradient_external - tidy3d.plugins.autograd.functions.morphological_gradient_internal - tidy3d.plugins.autograd.functions.morphological_gradient + tidy3d.plugins.autograd.differential_operators.grad + tidy3d.plugins.autograd.differential_operators.value_and_grad + +Functions +~~~~~~~~~ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.plugins.autograd.functions.add_at + tidy3d.plugins.autograd.functions.convolve tidy3d.plugins.autograd.functions.grey_closing - tidy3d.plugins.autograd.functions.grey_opening - tidy3d.plugins.autograd.functions.grey_erosion tidy3d.plugins.autograd.functions.grey_dilation + tidy3d.plugins.autograd.functions.grey_erosion + tidy3d.plugins.autograd.functions.grey_opening + tidy3d.plugins.autograd.functions.interpn + tidy3d.plugins.autograd.functions.least_squares + tidy3d.plugins.autograd.functions.morphological_gradient + tidy3d.plugins.autograd.functions.morphological_gradient_external + tidy3d.plugins.autograd.functions.morphological_gradient_internal tidy3d.plugins.autograd.functions.pad - tidy3d.plugins.autograd.functions.convolve + tidy3d.plugins.autograd.functions.rescale + tidy3d.plugins.autograd.functions.smooth_max + tidy3d.plugins.autograd.functions.smooth_min + tidy3d.plugins.autograd.functions.threshold + tidy3d.plugins.autograd.functions.trapz + +Utilities +~~~~~~~~~ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst tidy3d.plugins.autograd.utilities.chain - tidy3d.plugins.autograd.utilities.make_kernel tidy3d.plugins.autograd.utilities.get_kernel_size_px + tidy3d.plugins.autograd.utilities.make_kernel + tidy3d.plugins.autograd.utilities.scalar_objective + +Primitives +~~~~~~~~~~ + +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst tidy3d.plugins.autograd.primitives.gaussian_filter + tidy3d.plugins.autograd.primitives.interpolate_spline + +Inverse Design +~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: ../_autosummary/ + :template: module.rst + + tidy3d.plugins.autograd.invdes.CircularFilter + tidy3d.plugins.autograd.invdes.ConicFilter + tidy3d.plugins.autograd.invdes.ErosionDilationPenalty + tidy3d.plugins.autograd.invdes.FilterAndProject tidy3d.plugins.autograd.invdes.grey_indicator tidy3d.plugins.autograd.invdes.make_circular_filter tidy3d.plugins.autograd.invdes.make_conic_filter @@ -39,6 +85,3 @@ Automatic Differentiation with Autograd tidy3d.plugins.autograd.invdes.ramp_projection tidy3d.plugins.autograd.invdes.tanh_projection - tidy3d.plugins.autograd.types.PaddingType - tidy3d.plugins.autograd.types.KernelType - diff --git a/docs/api/spice.rst b/docs/api/spice.rst index b4eb08f7c9..81c4017757 100644 --- a/docs/api/spice.rst +++ b/docs/api/spice.rst @@ -11,6 +11,7 @@ Sources :template: module.rst tidy3d.DCVoltageSource + tidy3d.DCCurrentSource Analysis diff --git a/docs/api/submit_simulations.rst b/docs/api/submit_simulations.rst index 7f247947cf..7162f9fd52 100644 --- a/docs/api/submit_simulations.rst +++ b/docs/api/submit_simulations.rst @@ -1,4 +1,3 @@ - .. currentmodule:: tidy3d Submitting Simulations @@ -7,24 +6,74 @@ Submitting Simulations Generic Web API ---------------- +Core Workflow +~~~~~~~~~~~~~ + .. autosummary:: :toctree: _autosummary/ :template: module.rst tidy3d.web.api.webapi.run tidy3d.web.api.webapi.upload - tidy3d.web.api.webapi.estimate_cost - tidy3d.web.api.webapi.real_cost - tidy3d.web.api.webapi.get_info tidy3d.web.api.webapi.start tidy3d.web.api.webapi.monitor tidy3d.web.api.webapi.download tidy3d.web.api.webapi.load - tidy3d.web.api.webapi.delete - tidy3d.web.api.webapi.download_log + tidy3d.web.api.asynchronous.run_async + +Download Utilities +~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + tidy3d.web.api.webapi.download_json + tidy3d.web.api.webapi.download_hdf5 + tidy3d.web.api.webapi.download_log tidy3d.web.api.webapi.load_simulation - tidy3d.web.api.asynchronous.run_async + +Task Information +~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + + tidy3d.web.api.webapi.get_info + tidy3d.web.api.webapi.get_run_info + tidy3d.web.api.webapi.get_tasks + +Cost Estimation +~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + + tidy3d.web.api.webapi.estimate_cost + tidy3d.web.api.webapi.real_cost + +Task Management +~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + + tidy3d.web.api.webapi.delete + tidy3d.web.api.webapi.delete_old + tidy3d.web.api.webapi.abort + +Account and System +~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + + tidy3d.web.api.webapi.account + tidy3d.web.api.webapi.test Job and Batch Containers ------------------------- diff --git a/docs/api/viz.rst b/docs/api/viz.rst new file mode 100644 index 0000000000..46a3f4e94a --- /dev/null +++ b/docs/api/viz.rst @@ -0,0 +1,11 @@ +.. currentmodule:: tidy3d + +Visualization and Plotting +========================== + +.. autosummary:: + :toctree: _autosummary/ + :template: module.rst + + tidy3d.restore_matplotlib_rcparams + tidy3d.VisualizationSpec \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 9a5b62352f..f3794f771c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,6 +17,8 @@ # relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. # +from __future__ import annotations + import datetime import logging import os diff --git a/docs/development/recommendations.rst b/docs/development/recommendations.rst index d6d3d042ea..41555aa791 100644 --- a/docs/development/recommendations.rst +++ b/docs/development/recommendations.rst @@ -82,7 +82,7 @@ Managing Optional Dependencies On-The-Fly If you look within ``pyproject.toml``, it is possible to see that we have different packages relating to different functionalities that are optional. -Some examples from these are ``[vtk, jax, trimesh, gdstk, gdspy]`` etc. What we want to do is improve the import speed of the core-package in order to minimise small core operations. As we scale into a bigger package, decoupling these type of imports from the total pacakge import is essential. +Some examples from these are ``[vtk, jax, trimesh, gdstk]`` etc. What we want to do is improve the import speed of the core-package in order to minimise small core operations. As we scale into a bigger package, decoupling these type of imports from the total pacakge import is essential. Benchmarking Package Import @@ -94,4 +94,4 @@ We have a set of utilties to verify this. .. code:: - poetry run tidy3d develop benchmark-timing-operations \ No newline at end of file + poetry run tidy3d develop benchmark-timing-operations diff --git a/docs/development/release/index.rst b/docs/development/release/index.rst index d2958eaa7b..7fef279eed 100644 --- a/docs/development/release/index.rst +++ b/docs/development/release/index.rst @@ -16,6 +16,5 @@ This page contains all the relevant information relating to each version release .. include:: /development/release/flow.rst -.. include:: /development/release/version.rst .. include:: /development/release/documentation.rst -.. include:: /development/release/notebooks.rst \ No newline at end of file +.. include:: /development/release/notebooks.rst diff --git a/docs/development/release/version.rst b/docs/development/release/version.rst deleted file mode 100644 index 25f48ee05e..0000000000 --- a/docs/development/release/version.rst +++ /dev/null @@ -1,11 +0,0 @@ -Releasing a new ``tidy3d`` version ----------------------------------- - -This document contains the relevant information to create and publish a new tidy3d version. - -Version Information Management -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``pyproject.toml`` is declarative (ie static) and provides information to the packaging tools like PyPi on what version is ``tidy3d``. However, we also have a ``version.py`` file so that we can dynamically query ``tidy3d.__version__`` within our python version. These two files need to be kept with the same version. This is achieved by using the ``bump-my-version`` utility as described in the following section. **These files should not be manually updated.** - -The configuration of the way the version bumping occurs is described in the ``pyproject.toml``. \ No newline at end of file diff --git a/docs/faq b/docs/faq index 9b8479c00a..807ec8c174 160000 --- a/docs/faq +++ b/docs/faq @@ -1 +1 @@ -Subproject commit 9b8479c00a7b2d5fb81a90dd21c7b8e92423ef58 +Subproject commit 807ec8c174c575d339a4a847c64aeaa2ab8af59d diff --git a/docs/generate_doc.py b/docs/generate_doc.py index 0917f94ac5..a02fb9bbeb 100644 --- a/docs/generate_doc.py +++ b/docs/generate_doc.py @@ -1,4 +1,5 @@ # Generate documentation for Material Library (Python) +from __future__ import annotations import numpy as np @@ -24,8 +25,7 @@ def generate_material_library_doc(): def num2str(num): if np.isinf(num): return " " - else: - return str(round(num, 2)) + return str(round(num, 2)) with open(fname, "w") as f: # Write file header @@ -238,8 +238,7 @@ def generate_rf_material_library_doc(): def num2str(num): if np.isinf(num): return " " - else: - return str(round(num, 2)) + return str(round(num, 2)) with open(fname, "w") as f: # Write file header diff --git a/docs/install.rst b/docs/install.rst index 035acaaf94..75b757dad0 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -187,7 +187,6 @@ Tidy3D has several optional dependencies that provide additional functionality. Where ``dependency_group`` is one of the following: -- ``gdspy``: Adds support for GDS export using `gdspy `_. - ``gdstk``: Adds support for GDS export using `gdstk `_. - ``trimesh``: Support for more complex mesh handling and manipulation. - ``vtk``: Support for working with unstructured data. diff --git a/docs/notebooks b/docs/notebooks index 739cba22fb..49b82dad0f 160000 --- a/docs/notebooks +++ b/docs/notebooks @@ -1 +1 @@ -Subproject commit 739cba22fb53a6c6ec1414fae806fa8855be96cc +Subproject commit 49b82dad0f6d20063fe8c03e290d23221a453cbd diff --git a/poetry.lock b/poetry.lock index ec2c246581..3f8676a881 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,14 +2,14 @@ [[package]] name = "absl-py" -version = "2.2.0" +version = "2.3.1" description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py." optional = true python-versions = ">=3.8" groups = ["main"] files = [ - {file = "absl_py-2.2.0-py3-none-any.whl", hash = "sha256:5c432cdf7b045f89c4ddc3bba196cabb389c0c321322f8dec68eecdfa732fdad"}, - {file = "absl_py-2.2.0.tar.gz", hash = "sha256:2aabeae1403380e338fba88d4f8c9bf9925c20ad04c1c96d4a26930d034c507b"}, + {file = "absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d"}, + {file = "absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9"}, ] [[package]] @@ -109,26 +109,20 @@ files = [ [[package]] name = "argon2-cffi" -version = "23.1.0" +version = "25.1.0" description = "Argon2 for Python" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, - {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, + {file = "argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741"}, + {file = "argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1"}, ] [package.dependencies] argon2-cffi-bindings = "*" -[package.extras] -dev = ["argon2-cffi[tests,typing]", "tox (>4)"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] -tests = ["hypothesis", "pytest"] -typing = ["mypy"] - [[package]] name = "argon2-cffi-bindings" version = "21.2.0" @@ -191,19 +185,19 @@ test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock [[package]] name = "astroid" -version = "3.3.9" +version = "3.3.10" description = "An abstract syntax tree for Python with inference support." optional = true python-versions = ">=3.9.0" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "astroid-3.3.9-py3-none-any.whl", hash = "sha256:d05bfd0acba96a7bd43e222828b7d9bc1e138aaeb0649707908d3702a9831248"}, - {file = "astroid-3.3.9.tar.gz", hash = "sha256:622cc8e3048684aa42c820d9d218978021c3c3d174fb03a9f0d615921744f550"}, + {file = "astroid-3.3.10-py3-none-any.whl", hash = "sha256:104fb9cb9b27ea95e847a94c003be03a9e039334a8ebca5ee27dafaf5c5711eb"}, + {file = "astroid-3.3.10.tar.gz", hash = "sha256:c332157953060c6deb9caa57303ae0d20b0fbdb2e59b4a4f2a6ba49d0a7961ce"}, ] [package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4", markers = "python_version < \"3.11\""} [[package]] name = "asttokens" @@ -261,21 +255,22 @@ tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" a [[package]] name = "autograd" -version = "1.7.0" +version = "1.8.0" description = "Efficiently computes derivatives of NumPy code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "autograd-1.7.0-py3-none-any.whl", hash = "sha256:49680300f842f3a8722b060ac0d3ed7aca071d1ad4d3d38c9fdadafdcc73c30b"}, - {file = "autograd-1.7.0.tar.gz", hash = "sha256:de743fd368d6df523cd37305dcd171861a9752a144493677d2c9f5a56983ff2f"}, + {file = "autograd-1.8.0-py3-none-any.whl", hash = "sha256:4ab9084294f814cf56c280adbe19612546a35574d67c574b04933c7d2ecb7d78"}, + {file = "autograd-1.8.0.tar.gz", hash = "sha256:107374ded5b09fc8643ac925348c0369e7b0e73bbed9565ffd61b8fd04425683"}, ] [package.dependencies] -numpy = "*" +numpy = "<3" [package.extras] scipy = ["scipy"] +test = ["pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "babel" @@ -314,15 +309,15 @@ scipy = ">=1.0.0,<2.0.0" [[package]] name = "beautifulsoup4" -version = "4.13.3" +version = "4.13.4" description = "Screen-scraping library" optional = true python-versions = ">=3.7.0" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16"}, - {file = "beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b"}, + {file = "beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b"}, + {file = "beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195"}, ] [package.dependencies] @@ -406,107 +401,70 @@ css = ["tinycss2 (>=1.1.0,<1.5)"] [[package]] name = "boto3" -version = "1.37.17" +version = "1.39.3" description = "The AWS SDK for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "boto3-1.37.17-py3-none-any.whl", hash = "sha256:3e7c2056b0e7950818c4b8695ac0da3a7933cf9f4f45d67f8804ce37fdef8a7b"}, - {file = "boto3-1.37.17.tar.gz", hash = "sha256:f4ae383aca1799061d83c0097e9ccd7b494a71b36d72226628ad0fde1b95b7c9"}, + {file = "boto3-1.39.3-py3-none-any.whl", hash = "sha256:056cfa2440fe1a157a7c2be897c749c83e1a322144aa4dad889f2fca66571019"}, + {file = "boto3-1.39.3.tar.gz", hash = "sha256:0a367106497649ae3d8a7b571b8c3be01b7b935a0fe303d4cc2574ed03aecbb4"}, ] [package.dependencies] -botocore = ">=1.37.17,<1.38.0" +botocore = ">=1.39.3,<1.40.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.11.0,<0.12.0" +s3transfer = ">=0.13.0,<0.14.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.37.17" +version = "1.39.3" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "botocore-1.37.17-py3-none-any.whl", hash = "sha256:f8c93eec385a346c7a59efcb15d8cf3613cd9d6ab27f32492eed9549bd86d69e"}, - {file = "botocore-1.37.17.tar.gz", hash = "sha256:c879c2a5dc6952b81591d0e765c7b93e90df7f6c50b3d9b68011ec7cfe7fe48d"}, + {file = "botocore-1.39.3-py3-none-any.whl", hash = "sha256:66a81cfac18ad5e9f47696c73fdf44cdbd8f8ca51ab3fca1effca0aabf61f02f"}, + {file = "botocore-1.39.3.tar.gz", hash = "sha256:da8f477e119f9f8a3aaa8b3c99d9c6856ed0a243680aa3a3fbbfc15a8d4093fb"}, ] [package.dependencies] jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" urllib3 = [ - {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}, {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, + {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}, ] [package.extras] crt = ["awscrt (==0.23.8)"] -[[package]] -name = "bracex" -version = "2.5.post1" -description = "Bash style brace expander." -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6"}, - {file = "bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6"}, -] - -[[package]] -name = "bump-my-version" -version = "1.0.2" -description = "Version bump your Python project" -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "bump_my_version-1.0.2-py3-none-any.whl", hash = "sha256:61d350b8c71968dd4520fc6b9df8b982c7df254cd30858b8645eff0f4eaf380b"}, - {file = "bump_my_version-1.0.2.tar.gz", hash = "sha256:2f156877d2cdcda69afcb257ae4564c26e70f2fd5e5b15f2c7f26ab9e91502da"}, -] - -[package.dependencies] -click = "*" -httpx = ">=0.28.1" -pydantic = ">=2.0.0" -pydantic-settings = "*" -questionary = "*" -rich = "*" -rich-click = "*" -tomlkit = "*" -wcmatch = ">=8.5.1" - [[package]] name = "cachetools" -version = "5.5.2" +version = "6.1.0" description = "Extensible memoizing collections and decorators" optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a"}, - {file = "cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4"}, + {file = "cachetools-6.1.0-py3-none-any.whl", hash = "sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e"}, + {file = "cachetools-6.1.0.tar.gz", hash = "sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587"}, ] [[package]] name = "certifi" -version = "2025.1.31" +version = "2025.6.15" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" groups = ["main"] files = [ - {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, - {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, + {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"}, + {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"}, ] [[package]] @@ -618,104 +576,104 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.1" +version = "3.4.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, ] [[package]] @@ -746,6 +704,7 @@ description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, @@ -754,6 +713,22 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "click" +version = "8.2.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"}, + {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + [[package]] name = "cloudpickle" version = "3.1.1" @@ -768,15 +743,15 @@ files = [ [[package]] name = "cma" -version = "4.0.0" +version = "4.2.0" description = "CMA-ES, Covariance Matrix Adaptation Evolution Strategy for non-linear numerical optimization in Python" optional = true python-versions = "*" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "cma-4.0.0-py3-none-any.whl", hash = "sha256:97b86ba1ac9f1cbb189a06c4d4a78f591f0878e5dd3e55c95e88e622e78c1a10"}, - {file = "cma-4.0.0.tar.gz", hash = "sha256:fd28ce56983bf2fca0e614189d60134ebb80bf604f070d1ea095ea4e856f13a5"}, + {file = "cma-4.2.0-py3-none-any.whl", hash = "sha256:844dc93abaa427c5a37520586970c463dfce6f8aad5652e0fbd6e0229970f1ae"}, + {file = "cma-4.2.0.tar.gz", hash = "sha256:1868605e751f5dd9f1a4f8a9b7c8844a5abe8e93a729dc46be6c6c0550269b9f"}, ] [package.dependencies] @@ -906,67 +881,70 @@ test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist" [[package]] name = "contourpy" -version = "1.3.1" +version = "1.3.2" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "contourpy-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab"}, - {file = "contourpy-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124"}, - {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1"}, - {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b"}, - {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453"}, - {file = "contourpy-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3"}, - {file = "contourpy-1.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277"}, - {file = "contourpy-1.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595"}, - {file = "contourpy-1.3.1-cp310-cp310-win32.whl", hash = "sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697"}, - {file = "contourpy-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e"}, - {file = "contourpy-1.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3e8b974d8db2c5610fb4e76307e265de0edb655ae8169e8b21f41807ccbeec4b"}, - {file = "contourpy-1.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20914c8c973f41456337652a6eeca26d2148aa96dd7ac323b74516988bea89fc"}, - {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d40d37c1c3a4961b4619dd9d77b12124a453cc3d02bb31a07d58ef684d3d86"}, - {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:113231fe3825ebf6f15eaa8bc1f5b0ddc19d42b733345eae0934cb291beb88b6"}, - {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4dbbc03a40f916a8420e420d63e96a1258d3d1b58cbdfd8d1f07b49fcbd38e85"}, - {file = "contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a04ecd68acbd77fa2d39723ceca4c3197cb2969633836ced1bea14e219d077c"}, - {file = "contourpy-1.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c414fc1ed8ee1dbd5da626cf3710c6013d3d27456651d156711fa24f24bd1291"}, - {file = "contourpy-1.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:31c1b55c1f34f80557d3830d3dd93ba722ce7e33a0b472cba0ec3b6535684d8f"}, - {file = "contourpy-1.3.1-cp311-cp311-win32.whl", hash = "sha256:f611e628ef06670df83fce17805c344710ca5cde01edfdc72751311da8585375"}, - {file = "contourpy-1.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:b2bdca22a27e35f16794cf585832e542123296b4687f9fd96822db6bae17bfc9"}, - {file = "contourpy-1.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ffa84be8e0bd33410b17189f7164c3589c229ce5db85798076a3fa136d0e509"}, - {file = "contourpy-1.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805617228ba7e2cbbfb6c503858e626ab528ac2a32a04a2fe88ffaf6b02c32bc"}, - {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ade08d343436a94e633db932e7e8407fe7de8083967962b46bdfc1b0ced39454"}, - {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47734d7073fb4590b4a40122b35917cd77be5722d80683b249dac1de266aac80"}, - {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ba94a401342fc0f8b948e57d977557fbf4d515f03c67682dd5c6191cb2d16ec"}, - {file = "contourpy-1.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efa874e87e4a647fd2e4f514d5e91c7d493697127beb95e77d2f7561f6905bd9"}, - {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf98051f1045b15c87868dbaea84f92408337d4f81d0e449ee41920ea121d3b"}, - {file = "contourpy-1.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61332c87493b00091423e747ea78200659dc09bdf7fd69edd5e98cef5d3e9a8d"}, - {file = "contourpy-1.3.1-cp312-cp312-win32.whl", hash = "sha256:e914a8cb05ce5c809dd0fe350cfbb4e881bde5e2a38dc04e3afe1b3e58bd158e"}, - {file = "contourpy-1.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:08d9d449a61cf53033612cb368f3a1b26cd7835d9b8cd326647efe43bca7568d"}, - {file = "contourpy-1.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a761d9ccfc5e2ecd1bf05534eda382aa14c3e4f9205ba5b1684ecfe400716ef2"}, - {file = "contourpy-1.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:523a8ee12edfa36f6d2a49407f705a6ef4c5098de4f498619787e272de93f2d5"}, - {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece6df05e2c41bd46776fbc712e0996f7c94e0d0543af1656956d150c4ca7c81"}, - {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:573abb30e0e05bf31ed067d2f82500ecfdaec15627a59d63ea2d95714790f5c2"}, - {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fa36448e6a3a1a9a2ba23c02012c43ed88905ec80163f2ffe2421c7192a5d7"}, - {file = "contourpy-1.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ea9924d28fc5586bf0b42d15f590b10c224117e74409dd7a0be3b62b74a501c"}, - {file = "contourpy-1.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5b75aa69cb4d6f137b36f7eb2ace9280cfb60c55dc5f61c731fdf6f037f958a3"}, - {file = "contourpy-1.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1"}, - {file = "contourpy-1.3.1-cp313-cp313-win32.whl", hash = "sha256:36987a15e8ace5f58d4d5da9dca82d498c2bbb28dff6e5d04fbfcc35a9cb3a82"}, - {file = "contourpy-1.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:a7895f46d47671fa7ceec40f31fae721da51ad34bdca0bee83e38870b1f47ffd"}, - {file = "contourpy-1.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9ddeb796389dadcd884c7eb07bd14ef12408aaae358f0e2ae24114d797eede30"}, - {file = "contourpy-1.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:19c1555a6801c2f084c7ddc1c6e11f02eb6a6016ca1318dd5452ba3f613a1751"}, - {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:841ad858cff65c2c04bf93875e384ccb82b654574a6d7f30453a04f04af71342"}, - {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4318af1c925fb9a4fb190559ef3eec206845f63e80fb603d47f2d6d67683901c"}, - {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:14c102b0eab282427b662cb590f2e9340a9d91a1c297f48729431f2dcd16e14f"}, - {file = "contourpy-1.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda"}, - {file = "contourpy-1.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4d76d5993a34ef3df5181ba3c92fabb93f1eaa5729504fb03423fcd9f3177242"}, - {file = "contourpy-1.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:89785bb2a1980c1bd87f0cb1517a71cde374776a5f150936b82580ae6ead44a1"}, - {file = "contourpy-1.3.1-cp313-cp313t-win32.whl", hash = "sha256:8eb96e79b9f3dcadbad2a3891672f81cdcab7f95b27f28f1c67d75f045b6b4f1"}, - {file = "contourpy-1.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546"}, - {file = "contourpy-1.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6"}, - {file = "contourpy-1.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750"}, - {file = "contourpy-1.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53"}, - {file = "contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699"}, + {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, + {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512"}, + {file = "contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f"}, + {file = "contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2"}, + {file = "contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0"}, + {file = "contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445"}, + {file = "contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab"}, + {file = "contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83"}, + {file = "contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd"}, + {file = "contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f"}, + {file = "contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2"}, + {file = "contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415"}, + {file = "contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441"}, + {file = "contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e"}, + {file = "contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912"}, + {file = "contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb"}, + {file = "contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85"}, + {file = "contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422"}, + {file = "contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef"}, + {file = "contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f"}, + {file = "contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f"}, + {file = "contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532"}, + {file = "contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52"}, + {file = "contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd"}, + {file = "contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1"}, + {file = "contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16"}, + {file = "contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5"}, + {file = "contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5"}, + {file = "contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54"}, ] [package.dependencies] @@ -975,82 +953,86 @@ numpy = ">=1.23" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.11.1)", "types-Pillow"] +mypy = ["bokeh", "contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.15.0)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" -version = "7.7.0" +version = "7.9.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "coverage-7.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944"}, - {file = "coverage-7.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4"}, - {file = "coverage-7.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98"}, - {file = "coverage-7.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f"}, - {file = "coverage-7.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd"}, - {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b"}, - {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c"}, - {file = "coverage-7.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054"}, - {file = "coverage-7.7.0-cp310-cp310-win32.whl", hash = "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee"}, - {file = "coverage-7.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3"}, - {file = "coverage-7.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7"}, - {file = "coverage-7.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656"}, - {file = "coverage-7.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b"}, - {file = "coverage-7.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b"}, - {file = "coverage-7.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd"}, - {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba"}, - {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608"}, - {file = "coverage-7.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5"}, - {file = "coverage-7.7.0-cp311-cp311-win32.whl", hash = "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a"}, - {file = "coverage-7.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4"}, - {file = "coverage-7.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94"}, - {file = "coverage-7.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db"}, - {file = "coverage-7.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe"}, - {file = "coverage-7.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8"}, - {file = "coverage-7.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135"}, - {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705"}, - {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0"}, - {file = "coverage-7.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd"}, - {file = "coverage-7.7.0-cp312-cp312-win32.whl", hash = "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d"}, - {file = "coverage-7.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92"}, - {file = "coverage-7.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072"}, - {file = "coverage-7.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82"}, - {file = "coverage-7.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa"}, - {file = "coverage-7.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f"}, - {file = "coverage-7.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265"}, - {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2"}, - {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d"}, - {file = "coverage-7.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39"}, - {file = "coverage-7.7.0-cp313-cp313-win32.whl", hash = "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68"}, - {file = "coverage-7.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573"}, - {file = "coverage-7.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322"}, - {file = "coverage-7.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce"}, - {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816"}, - {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf"}, - {file = "coverage-7.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57"}, - {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4"}, - {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c"}, - {file = "coverage-7.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463"}, - {file = "coverage-7.7.0-cp313-cp313t-win32.whl", hash = "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90"}, - {file = "coverage-7.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07"}, - {file = "coverage-7.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5"}, - {file = "coverage-7.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261"}, - {file = "coverage-7.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253"}, - {file = "coverage-7.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf"}, - {file = "coverage-7.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e"}, - {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b"}, - {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e"}, - {file = "coverage-7.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d"}, - {file = "coverage-7.7.0-cp39-cp39-win32.whl", hash = "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c"}, - {file = "coverage-7.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59"}, - {file = "coverage-7.7.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c"}, - {file = "coverage-7.7.0-py3-none-any.whl", hash = "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a"}, - {file = "coverage-7.7.0.tar.gz", hash = "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166"}, + {file = "coverage-7.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:66283a192a14a3854b2e7f3418d7db05cdf411012ab7ff5db98ff3b181e1f912"}, + {file = "coverage-7.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4e01d138540ef34fcf35c1aa24d06c3de2a4cffa349e29a10056544f35cca15f"}, + {file = "coverage-7.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f22627c1fe2745ee98d3ab87679ca73a97e75ca75eb5faee48660d060875465f"}, + {file = "coverage-7.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b1c2d8363247b46bd51f393f86c94096e64a1cf6906803fa8d5a9d03784bdbf"}, + {file = "coverage-7.9.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c10c882b114faf82dbd33e876d0cbd5e1d1ebc0d2a74ceef642c6152f3f4d547"}, + {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:de3c0378bdf7066c3988d66cd5232d161e933b87103b014ab1b0b4676098fa45"}, + {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1e2f097eae0e5991e7623958a24ced3282676c93c013dde41399ff63e230fcf2"}, + {file = "coverage-7.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28dc1f67e83a14e7079b6cea4d314bc8b24d1aed42d3582ff89c0295f09b181e"}, + {file = "coverage-7.9.2-cp310-cp310-win32.whl", hash = "sha256:bf7d773da6af9e10dbddacbf4e5cab13d06d0ed93561d44dae0188a42c65be7e"}, + {file = "coverage-7.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:0c0378ba787681ab1897f7c89b415bd56b0b2d9a47e5a3d8dc0ea55aac118d6c"}, + {file = "coverage-7.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a7a56a2964a9687b6aba5b5ced6971af308ef6f79a91043c05dd4ee3ebc3e9ba"}, + {file = "coverage-7.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123d589f32c11d9be7fe2e66d823a236fe759b0096f5db3fb1b75b2fa414a4fa"}, + {file = "coverage-7.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:333b2e0ca576a7dbd66e85ab402e35c03b0b22f525eed82681c4b866e2e2653a"}, + {file = "coverage-7.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:326802760da234baf9f2f85a39e4a4b5861b94f6c8d95251f699e4f73b1835dc"}, + {file = "coverage-7.9.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19e7be4cfec248df38ce40968c95d3952fbffd57b400d4b9bb580f28179556d2"}, + {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0b4a4cb73b9f2b891c1788711408ef9707666501ba23684387277ededab1097c"}, + {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2c8937fa16c8c9fbbd9f118588756e7bcdc7e16a470766a9aef912dd3f117dbd"}, + {file = "coverage-7.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:42da2280c4d30c57a9b578bafd1d4494fa6c056d4c419d9689e66d775539be74"}, + {file = "coverage-7.9.2-cp311-cp311-win32.whl", hash = "sha256:14fa8d3da147f5fdf9d298cacc18791818f3f1a9f542c8958b80c228320e90c6"}, + {file = "coverage-7.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:549cab4892fc82004f9739963163fd3aac7a7b0df430669b75b86d293d2df2a7"}, + {file = "coverage-7.9.2-cp311-cp311-win_arm64.whl", hash = "sha256:c2667a2b913e307f06aa4e5677f01a9746cd08e4b35e14ebcde6420a9ebb4c62"}, + {file = "coverage-7.9.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae9eb07f1cfacd9cfe8eaee6f4ff4b8a289a668c39c165cd0c8548484920ffc0"}, + {file = "coverage-7.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ce85551f9a1119f02adc46d3014b5ee3f765deac166acf20dbb851ceb79b6f3"}, + {file = "coverage-7.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8f6389ac977c5fb322e0e38885fbbf901743f79d47f50db706e7644dcdcb6e1"}, + {file = "coverage-7.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff0d9eae8cdfcd58fe7893b88993723583a6ce4dfbfd9f29e001922544f95615"}, + {file = "coverage-7.9.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fae939811e14e53ed8a9818dad51d434a41ee09df9305663735f2e2d2d7d959b"}, + {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:31991156251ec202c798501e0a42bbdf2169dcb0f137b1f5c0f4267f3fc68ef9"}, + {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d0d67963f9cbfc7c7f96d4ac74ed60ecbebd2ea6eeb51887af0f8dce205e545f"}, + {file = "coverage-7.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:49b752a2858b10580969ec6af6f090a9a440a64a301ac1528d7ca5f7ed497f4d"}, + {file = "coverage-7.9.2-cp312-cp312-win32.whl", hash = "sha256:88d7598b8ee130f32f8a43198ee02edd16d7f77692fa056cb779616bbea1b355"}, + {file = "coverage-7.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:9dfb070f830739ee49d7c83e4941cc767e503e4394fdecb3b54bfdac1d7662c0"}, + {file = "coverage-7.9.2-cp312-cp312-win_arm64.whl", hash = "sha256:4e2c058aef613e79df00e86b6d42a641c877211384ce5bd07585ed7ba71ab31b"}, + {file = "coverage-7.9.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:985abe7f242e0d7bba228ab01070fde1d6c8fa12f142e43debe9ed1dde686038"}, + {file = "coverage-7.9.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82c3939264a76d44fde7f213924021ed31f55ef28111a19649fec90c0f109e6d"}, + {file = "coverage-7.9.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae5d563e970dbe04382f736ec214ef48103d1b875967c89d83c6e3f21706d5b3"}, + {file = "coverage-7.9.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdd612e59baed2a93c8843c9a7cb902260f181370f1d772f4842987535071d14"}, + {file = "coverage-7.9.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:256ea87cb2a1ed992bcdfc349d8042dcea1b80436f4ddf6e246d6bee4b5d73b6"}, + {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f44ae036b63c8ea432f610534a2668b0c3aee810e7037ab9d8ff6883de480f5b"}, + {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82d76ad87c932935417a19b10cfe7abb15fd3f923cfe47dbdaa74ef4e503752d"}, + {file = "coverage-7.9.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:619317bb86de4193debc712b9e59d5cffd91dc1d178627ab2a77b9870deb2868"}, + {file = "coverage-7.9.2-cp313-cp313-win32.whl", hash = "sha256:0a07757de9feb1dfafd16ab651e0f628fd7ce551604d1bf23e47e1ddca93f08a"}, + {file = "coverage-7.9.2-cp313-cp313-win_amd64.whl", hash = "sha256:115db3d1f4d3f35f5bb021e270edd85011934ff97c8797216b62f461dd69374b"}, + {file = "coverage-7.9.2-cp313-cp313-win_arm64.whl", hash = "sha256:48f82f889c80af8b2a7bb6e158d95a3fbec6a3453a1004d04e4f3b5945a02694"}, + {file = "coverage-7.9.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:55a28954545f9d2f96870b40f6c3386a59ba8ed50caf2d949676dac3ecab99f5"}, + {file = "coverage-7.9.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cdef6504637731a63c133bb2e6f0f0214e2748495ec15fe42d1e219d1b133f0b"}, + {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcd5ebe66c7a97273d5d2ddd4ad0ed2e706b39630ed4b53e713d360626c3dbb3"}, + {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9303aed20872d7a3c9cb39c5d2b9bdbe44e3a9a1aecb52920f7e7495410dfab8"}, + {file = "coverage-7.9.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc18ea9e417a04d1920a9a76fe9ebd2f43ca505b81994598482f938d5c315f46"}, + {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6406cff19880aaaadc932152242523e892faff224da29e241ce2fca329866584"}, + {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:2d0d4f6ecdf37fcc19c88fec3e2277d5dee740fb51ffdd69b9579b8c31e4232e"}, + {file = "coverage-7.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c33624f50cf8de418ab2b4d6ca9eda96dc45b2c4231336bac91454520e8d1fac"}, + {file = "coverage-7.9.2-cp313-cp313t-win32.whl", hash = "sha256:1df6b76e737c6a92210eebcb2390af59a141f9e9430210595251fbaf02d46926"}, + {file = "coverage-7.9.2-cp313-cp313t-win_amd64.whl", hash = "sha256:f5fd54310b92741ebe00d9c0d1d7b2b27463952c022da6d47c175d246a98d1bd"}, + {file = "coverage-7.9.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c48c2375287108c887ee87d13b4070a381c6537d30e8487b24ec721bf2a781cb"}, + {file = "coverage-7.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ddc39510ac922a5c4c27849b739f875d3e1d9e590d1e7b64c98dadf037a16cce"}, + {file = "coverage-7.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a535c0c7364acd55229749c2b3e5eebf141865de3a8f697076a3291985f02d30"}, + {file = "coverage-7.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df0f9ef28e0f20c767ccdccfc5ae5f83a6f4a2fbdfbcbcc8487a8a78771168c8"}, + {file = "coverage-7.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f3da12e0ccbcb348969221d29441ac714bbddc4d74e13923d3d5a7a0bebef7a"}, + {file = "coverage-7.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a17eaf46f56ae0f870f14a3cbc2e4632fe3771eab7f687eda1ee59b73d09fe4"}, + {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:669135a9d25df55d1ed56a11bf555f37c922cf08d80799d4f65d77d7d6123fcf"}, + {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9d3a700304d01a627df9db4322dc082a0ce1e8fc74ac238e2af39ced4c083193"}, + {file = "coverage-7.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:71ae8b53855644a0b1579d4041304ddc9995c7b21c8a1f16753c4d8903b4dfed"}, + {file = "coverage-7.9.2-cp39-cp39-win32.whl", hash = "sha256:dd7a57b33b5cf27acb491e890720af45db05589a80c1ffc798462a765be6d4d7"}, + {file = "coverage-7.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f65bb452e579d5540c8b37ec105dd54d8b9307b07bcaa186818c104ffda22441"}, + {file = "coverage-7.9.2-pp39.pp310.pp311-none-any.whl", hash = "sha256:8a1166db2fb62473285bcb092f586e081e92656c7dfa8e9f62b4d39d7e6b5050"}, + {file = "coverage-7.9.2-py3-none-any.whl", hash = "sha256:e425cd5b00f6fc0ed7cdbd766c70be8baab4b7839e4d4fe5fac48581dd968ea4"}, + {file = "coverage-7.9.2.tar.gz", hash = "sha256:997024fa51e3290264ffd7492ec97d0690293ccd2b45a6cd7d82d945a4a80c8b"}, ] [package.dependencies] @@ -1108,15 +1090,15 @@ test = ["pandas[test]", "pre-commit", "pytest", "pytest-cov", "pytest-rerunfailu [[package]] name = "dask" -version = "2025.2.0" +version = "2025.5.1" description = "Parallel PyData with Task Scheduling" optional = false python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "dask-2025.2.0-py3-none-any.whl", hash = "sha256:f0fdeef6ceb0a06569d456c9e704f220f7f54e80f3a6ea42ab98cea6bc642b6e"}, - {file = "dask-2025.2.0.tar.gz", hash = "sha256:89c87125d04d28141eaccc4794164ce9098163fd22d8ad943db48f8d4c815460"}, + {file = "dask-2025.5.1-py3-none-any.whl", hash = "sha256:3b85fdaa5f6f989dde49da6008415b1ae996985ebdfb1e40de2c997d9010371d"}, + {file = "dask-2025.5.1.tar.gz", hash = "sha256:979d9536549de0e463f4cab8a8c66c3a2ef55791cd740d07d9bf58fab1d1076a"}, ] [package.dependencies] @@ -1134,44 +1116,44 @@ array = ["numpy (>=1.24)"] complete = ["dask[array,dataframe,diagnostics,distributed]", "lz4 (>=4.3.2)", "pyarrow (>=14.0.1)"] dataframe = ["dask[array]", "pandas (>=2.0)", "pyarrow (>=14.0.1)"] diagnostics = ["bokeh (>=3.1.0)", "jinja2 (>=2.10.3)"] -distributed = ["distributed (==2025.2.0)"] +distributed = ["distributed (==2025.5.1)"] test = ["pandas[test]", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytest-rerunfailures", "pytest-timeout", "pytest-xdist"] [[package]] name = "debugpy" -version = "1.8.13" +version = "1.8.14" description = "An implementation of the Debug Adapter Protocol for Python" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "debugpy-1.8.13-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:06859f68e817966723ffe046b896b1bd75c665996a77313370336ee9e1de3e90"}, - {file = "debugpy-1.8.13-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb56c2db69fb8df3168bc857d7b7d2494fed295dfdbde9a45f27b4b152f37520"}, - {file = "debugpy-1.8.13-cp310-cp310-win32.whl", hash = "sha256:46abe0b821cad751fc1fb9f860fb2e68d75e2c5d360986d0136cd1db8cad4428"}, - {file = "debugpy-1.8.13-cp310-cp310-win_amd64.whl", hash = "sha256:dc7b77f5d32674686a5f06955e4b18c0e41fb5a605f5b33cf225790f114cfeec"}, - {file = "debugpy-1.8.13-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff"}, - {file = "debugpy-1.8.13-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377"}, - {file = "debugpy-1.8.13-cp311-cp311-win32.whl", hash = "sha256:7d9a05efc6973b5aaf076d779cf3a6bbb1199e059a17738a2aa9d27a53bcc888"}, - {file = "debugpy-1.8.13-cp311-cp311-win_amd64.whl", hash = "sha256:62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc"}, - {file = "debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1"}, - {file = "debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522"}, - {file = "debugpy-1.8.13-cp312-cp312-win32.whl", hash = "sha256:3872ce5453b17837ef47fb9f3edc25085ff998ce63543f45ba7af41e7f7d370f"}, - {file = "debugpy-1.8.13-cp312-cp312-win_amd64.whl", hash = "sha256:63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea"}, - {file = "debugpy-1.8.13-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:31abc9618be4edad0b3e3a85277bc9ab51a2d9f708ead0d99ffb5bb750e18503"}, - {file = "debugpy-1.8.13-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0bd87557f97bced5513a74088af0b84982b6ccb2e254b9312e29e8a5c4270eb"}, - {file = "debugpy-1.8.13-cp313-cp313-win32.whl", hash = "sha256:5268ae7fdca75f526d04465931cb0bd24577477ff50e8bb03dab90983f4ebd02"}, - {file = "debugpy-1.8.13-cp313-cp313-win_amd64.whl", hash = "sha256:79ce4ed40966c4c1631d0131606b055a5a2f8e430e3f7bf8fd3744b09943e8e8"}, - {file = "debugpy-1.8.13-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:acf39a6e98630959763f9669feddee540745dfc45ad28dbc9bd1f9cd60639391"}, - {file = "debugpy-1.8.13-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:924464d87e7d905eb0d79fb70846558910e906d9ee309b60c4fe597a2e802590"}, - {file = "debugpy-1.8.13-cp38-cp38-win32.whl", hash = "sha256:3dae443739c6b604802da9f3e09b0f45ddf1cf23c99161f3a1a8039f61a8bb89"}, - {file = "debugpy-1.8.13-cp38-cp38-win_amd64.whl", hash = "sha256:ed93c3155fc1f888ab2b43626182174e457fc31b7781cd1845629303790b8ad1"}, - {file = "debugpy-1.8.13-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:6fab771639332bd8ceb769aacf454a30d14d7a964f2012bf9c4e04c60f16e85b"}, - {file = "debugpy-1.8.13-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32b6857f8263a969ce2ca098f228e5cc0604d277447ec05911a8c46cf3e7e307"}, - {file = "debugpy-1.8.13-cp39-cp39-win32.whl", hash = "sha256:f14d2c4efa1809da125ca62df41050d9c7cd9cb9e380a2685d1e453c4d450ccb"}, - {file = "debugpy-1.8.13-cp39-cp39-win_amd64.whl", hash = "sha256:ea869fe405880327497e6945c09365922c79d2a1eed4c3ae04d77ac7ae34b2b5"}, - {file = "debugpy-1.8.13-py2.py3-none-any.whl", hash = "sha256:d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f"}, - {file = "debugpy-1.8.13.tar.gz", hash = "sha256:837e7bef95bdefba426ae38b9a94821ebdc5bea55627879cd48165c90b9e50ce"}, + {file = "debugpy-1.8.14-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:93fee753097e85623cab1c0e6a68c76308cd9f13ffdf44127e6fab4fbf024339"}, + {file = "debugpy-1.8.14-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d937d93ae4fa51cdc94d3e865f535f185d5f9748efb41d0d49e33bf3365bd79"}, + {file = "debugpy-1.8.14-cp310-cp310-win32.whl", hash = "sha256:c442f20577b38cc7a9aafecffe1094f78f07fb8423c3dddb384e6b8f49fd2987"}, + {file = "debugpy-1.8.14-cp310-cp310-win_amd64.whl", hash = "sha256:f117dedda6d969c5c9483e23f573b38f4e39412845c7bc487b6f2648df30fe84"}, + {file = "debugpy-1.8.14-cp311-cp311-macosx_14_0_universal2.whl", hash = "sha256:1b2ac8c13b2645e0b1eaf30e816404990fbdb168e193322be8f545e8c01644a9"}, + {file = "debugpy-1.8.14-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf431c343a99384ac7eab2f763980724834f933a271e90496944195318c619e2"}, + {file = "debugpy-1.8.14-cp311-cp311-win32.whl", hash = "sha256:c99295c76161ad8d507b413cd33422d7c542889fbb73035889420ac1fad354f2"}, + {file = "debugpy-1.8.14-cp311-cp311-win_amd64.whl", hash = "sha256:7816acea4a46d7e4e50ad8d09d963a680ecc814ae31cdef3622eb05ccacf7b01"}, + {file = "debugpy-1.8.14-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:8899c17920d089cfa23e6005ad9f22582fd86f144b23acb9feeda59e84405b84"}, + {file = "debugpy-1.8.14-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6bb5c0dcf80ad5dbc7b7d6eac484e2af34bdacdf81df09b6a3e62792b722826"}, + {file = "debugpy-1.8.14-cp312-cp312-win32.whl", hash = "sha256:281d44d248a0e1791ad0eafdbbd2912ff0de9eec48022a5bfbc332957487ed3f"}, + {file = "debugpy-1.8.14-cp312-cp312-win_amd64.whl", hash = "sha256:5aa56ef8538893e4502a7d79047fe39b1dae08d9ae257074c6464a7b290b806f"}, + {file = "debugpy-1.8.14-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:329a15d0660ee09fec6786acdb6e0443d595f64f5d096fc3e3ccf09a4259033f"}, + {file = "debugpy-1.8.14-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f920c7f9af409d90f5fd26e313e119d908b0dd2952c2393cd3247a462331f15"}, + {file = "debugpy-1.8.14-cp313-cp313-win32.whl", hash = "sha256:3784ec6e8600c66cbdd4ca2726c72d8ca781e94bce2f396cc606d458146f8f4e"}, + {file = "debugpy-1.8.14-cp313-cp313-win_amd64.whl", hash = "sha256:684eaf43c95a3ec39a96f1f5195a7ff3d4144e4a18d69bb66beeb1a6de605d6e"}, + {file = "debugpy-1.8.14-cp38-cp38-macosx_14_0_x86_64.whl", hash = "sha256:d5582bcbe42917bc6bbe5c12db1bffdf21f6bfc28d4554b738bf08d50dc0c8c3"}, + {file = "debugpy-1.8.14-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5349b7c3735b766a281873fbe32ca9cca343d4cc11ba4a743f84cb854339ff35"}, + {file = "debugpy-1.8.14-cp38-cp38-win32.whl", hash = "sha256:7118d462fe9724c887d355eef395fae68bc764fd862cdca94e70dcb9ade8a23d"}, + {file = "debugpy-1.8.14-cp38-cp38-win_amd64.whl", hash = "sha256:d235e4fa78af2de4e5609073972700523e372cf5601742449970110d565ca28c"}, + {file = "debugpy-1.8.14-cp39-cp39-macosx_14_0_x86_64.whl", hash = "sha256:413512d35ff52c2fb0fd2d65e69f373ffd24f0ecb1fac514c04a668599c5ce7f"}, + {file = "debugpy-1.8.14-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c9156f7524a0d70b7a7e22b2e311d8ba76a15496fb00730e46dcdeedb9e1eea"}, + {file = "debugpy-1.8.14-cp39-cp39-win32.whl", hash = "sha256:b44985f97cc3dd9d52c42eb59ee9d7ee0c4e7ecd62bca704891f997de4cef23d"}, + {file = "debugpy-1.8.14-cp39-cp39-win_amd64.whl", hash = "sha256:b1528cfee6c1b1c698eb10b6b096c598738a8238822d218173d21c3086de8123"}, + {file = "debugpy-1.8.14-py2.py3-none-any.whl", hash = "sha256:5cd9a579d553b6cb9759a7908a41988ee6280b961f24f63336835d9418216a20"}, + {file = "debugpy-1.8.14.tar.gz", hash = "sha256:7cd287184318416850aa8b60ac90105837bb1e59531898c07569d197d2ed5322"}, ] [[package]] @@ -1215,17 +1197,39 @@ files = [ {file = "devsim-2.9.1-cp37-abi3-win_amd64.whl", hash = "sha256:36243a15ac1e93db827841d88805d9ae61e82e8c09a3cbeba010240846d2ae9d"}, ] +[[package]] +name = "diff-cover" +version = "9.4.1" +description = "Run coverage and linting reports on diffs" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"dev\"" +files = [ + {file = "diff_cover-9.4.1-py3-none-any.whl", hash = "sha256:84d5bd402f566d04212126988a2c352b8ec801fa7e43b8856bd8dc146baec5a9"}, + {file = "diff_cover-9.4.1.tar.gz", hash = "sha256:7ded89e5fb3a61161be9b98d025f2ad4f5aa95de593c3fbeb65419ddb6667610"}, +] + +[package.dependencies] +chardet = ">=3.0.0" +Jinja2 = ">=2.7.1" +pluggy = ">=0.13.1,<2" +Pygments = ">=2.19.1,<3.0.0" + +[package.extras] +toml = ["tomli (>=1.2.1)"] + [[package]] name = "dill" -version = "0.3.9" +version = "0.4.0" description = "serialize all of Python" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, - {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, + {file = "dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049"}, + {file = "dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0"}, ] [package.extras] @@ -1313,10 +1317,7 @@ files = [ [package.dependencies] fsspec = {version = "*", optional = true, markers = "extra == \"epath\""} importlib_resources = {version = "*", optional = true, markers = "extra == \"epath\""} -typing_extensions = [ - {version = "*", optional = true, markers = "extra == \"epy\""}, - {version = "*", optional = true, markers = "extra == \"epath\" or extra == \"epy\""}, -] +typing_extensions = {version = "*", optional = true, markers = "extra == \"epath\" or extra == \"epy\""} zipp = {version = "*", optional = true, markers = "extra == \"epath\""} [package.extras] @@ -1341,17 +1342,20 @@ lazy-imports = ["etils[ecolab]"] [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["main"] markers = "python_version <= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] @@ -1389,15 +1393,15 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastcore" -version = "1.8.0" +version = "1.8.5" description = "Python supercharged for fastai development" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "fastcore-1.8.0-py3-none-any.whl", hash = "sha256:67739747f0f714d02944957271a11dcb4a9dd40012615e6f9d19add3e5d9e041"}, - {file = "fastcore-1.8.0.tar.gz", hash = "sha256:d23e63aff4bcd06dde24cdf9f7ea13c48e7d274ae89e52e826df33c64869c976"}, + {file = "fastcore-1.8.5-py3-none-any.whl", hash = "sha256:84b0301691926a2fd2ea45f0cc66a0fbb4b531244d2995cf69e67db75b4a40f6"}, + {file = "fastcore-1.8.5.tar.gz", hash = "sha256:5b6549f44f8df2d81ec378885c17a6a706a02bb40e38f14f6b44f5296180b76d"}, ] [package.dependencies] @@ -1470,23 +1474,23 @@ testing = ["black[jupyter] (==23.7.0)", "clu", "clu (<=0.0.9) ; python_version < [[package]] name = "flax" -version = "0.10.4" +version = "0.10.6" description = "Flax: A neural network library for JAX designed for flexibility" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "flax-0.10.4-py3-none-any.whl", hash = "sha256:8cc83d91654ff943909730e02e858b4cd4577531373f83abe6597c58c581032d"}, - {file = "flax-0.10.4.tar.gz", hash = "sha256:57ae44d3f111fc85cff9049adb9684ce8ebd44e87bd8ca776ed52422c2d85021"}, + {file = "flax-0.10.6-py3-none-any.whl", hash = "sha256:86a5f0ba0f1603c687714999b58a4e362e784a6d2dc5a510b18a8e7a6c729e18"}, + {file = "flax-0.10.6.tar.gz", hash = "sha256:8f3d1eb7de9bbaa18e08d0423dce890aef88a8b9dc6daa23baa631e8dfb09618"}, ] [package.dependencies] -jax = ">=0.4.27" +jax = ">=0.5.1" msgpack = "*" numpy = [ {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, - {version = ">=1.23.2", markers = "python_version == \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] optax = "*" orbax-checkpoint = "*" @@ -1498,68 +1502,60 @@ typing_extensions = ">=4.2" [package.extras] all = ["matplotlib"] -dev = ["pre-commit (>=3.8.0)"] +dev = ["nanobind (>=2.5.0)", "pre-commit (>=3.8.0)", "scikit-build-core[pyproject] (>=0.11.0)"] docs = ["Pygments (>=2.6.1)", "dm-haiku", "docutils (==0.16)", "einops", "ipykernel", "ipython_genutils", "ipywidgets (>=8.1.5)", "jupytext (==1.13.8)", "kagglehub (>=0.3.3)", "matplotlib", "ml_collections", "myst_nb", "nbstripout", "recommonmark", "scikit-learn", "sphinx (>=3.3.1)", "sphinx-book-theme", "sphinx-design"] -testing = ["cloudpickle (>=3.0.0)", "clu", "clu (<=0.0.9) ; python_version < \"3.10\"", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jaxtyping", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "opencv-python", "pytest", "pytest-cov", "pytest-custom_exit_code", "pytest-xdist", "pytype", "sentencepiece", "tensorflow (>=2.12.0)", "tensorflow_datasets", "tensorflow_text (>=2.11.0) ; platform_system != \"Darwin\"", "torch", "treescope (>=0.1.1) ; python_version >= \"3.10\""] +testing = ["ale-py (>=0.10.2)", "cloudpickle (>=3.0.0)", "clu", "clu (<=0.0.9) ; python_version < \"3.10\"", "einops", "gymnasium[accept-rom-license,atari]", "jaxlib", "jaxtyping", "jraph (>=0.0.6dev0)", "ml-collections", "mypy", "opencv-python", "pytest", "pytest-cov", "pytest-custom_exit_code", "pytest-xdist", "pytype", "sentencepiece", "tensorflow (>=2.12.0)", "tensorflow_datasets", "tensorflow_text (>=2.11.0) ; platform_system != \"Darwin\"", "torch", "treescope (>=0.1.1) ; python_version >= \"3.10\""] [[package]] name = "fonttools" -version = "4.56.0" +version = "4.58.5" description = "Tools to manipulate font files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "fonttools-4.56.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:331954d002dbf5e704c7f3756028e21db07097c19722569983ba4d74df014000"}, - {file = "fonttools-4.56.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8d1613abd5af2f93c05867b3a3759a56e8bf97eb79b1da76b2bc10892f96ff16"}, - {file = "fonttools-4.56.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:705837eae384fe21cee5e5746fd4f4b2f06f87544fa60f60740007e0aa600311"}, - {file = "fonttools-4.56.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc871904a53a9d4d908673c6faa15689874af1c7c5ac403a8e12d967ebd0c0dc"}, - {file = "fonttools-4.56.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38b947de71748bab150259ee05a775e8a0635891568e9fdb3cdd7d0e0004e62f"}, - {file = "fonttools-4.56.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:86b2a1013ef7a64d2e94606632683f07712045ed86d937c11ef4dde97319c086"}, - {file = "fonttools-4.56.0-cp310-cp310-win32.whl", hash = "sha256:133bedb9a5c6376ad43e6518b7e2cd2f866a05b1998f14842631d5feb36b5786"}, - {file = "fonttools-4.56.0-cp310-cp310-win_amd64.whl", hash = "sha256:17f39313b649037f6c800209984a11fc256a6137cbe5487091c6c7187cae4685"}, - {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ef04bc7827adb7532be3d14462390dd71287644516af3f1e67f1e6ff9c6d6df"}, - {file = "fonttools-4.56.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ffda9b8cd9cb8b301cae2602ec62375b59e2e2108a117746f12215145e3f786c"}, - {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e993e8db36306cc3f1734edc8ea67906c55f98683d6fd34c3fc5593fdbba4c"}, - {file = "fonttools-4.56.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:003548eadd674175510773f73fb2060bb46adb77c94854af3e0cc5bc70260049"}, - {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd9825822e7bb243f285013e653f6741954d8147427aaa0324a862cdbf4cbf62"}, - {file = "fonttools-4.56.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b23d30a2c0b992fb1c4f8ac9bfde44b5586d23457759b6cf9a787f1a35179ee0"}, - {file = "fonttools-4.56.0-cp311-cp311-win32.whl", hash = "sha256:47b5e4680002ae1756d3ae3b6114e20aaee6cc5c69d1e5911f5ffffd3ee46c6b"}, - {file = "fonttools-4.56.0-cp311-cp311-win_amd64.whl", hash = "sha256:14a3e3e6b211660db54ca1ef7006401e4a694e53ffd4553ab9bc87ead01d0f05"}, - {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6f195c14c01bd057bc9b4f70756b510e009c83c5ea67b25ced3e2c38e6ee6e9"}, - {file = "fonttools-4.56.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fa760e5fe8b50cbc2d71884a1eff2ed2b95a005f02dda2fa431560db0ddd927f"}, - {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d54a45d30251f1d729e69e5b675f9a08b7da413391a1227781e2a297fa37f6d2"}, - {file = "fonttools-4.56.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661a8995d11e6e4914a44ca7d52d1286e2d9b154f685a4d1f69add8418961563"}, - {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9d94449ad0a5f2a8bf5d2f8d71d65088aee48adbe45f3c5f8e00e3ad861ed81a"}, - {file = "fonttools-4.56.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f59746f7953f69cc3290ce2f971ab01056e55ddd0fb8b792c31a8acd7fee2d28"}, - {file = "fonttools-4.56.0-cp312-cp312-win32.whl", hash = "sha256:bce60f9a977c9d3d51de475af3f3581d9b36952e1f8fc19a1f2254f1dda7ce9c"}, - {file = "fonttools-4.56.0-cp312-cp312-win_amd64.whl", hash = "sha256:300c310bb725b2bdb4f5fc7e148e190bd69f01925c7ab437b9c0ca3e1c7cd9ba"}, - {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f20e2c0dfab82983a90f3d00703ac0960412036153e5023eed2b4641d7d5e692"}, - {file = "fonttools-4.56.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f36a0868f47b7566237640c026c65a86d09a3d9ca5df1cd039e30a1da73098a0"}, - {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62b4c6802fa28e14dba010e75190e0e6228513573f1eeae57b11aa1a39b7e5b1"}, - {file = "fonttools-4.56.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a05d1f07eb0a7d755fbe01fee1fd255c3a4d3730130cf1bfefb682d18fd2fcea"}, - {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0073b62c3438cf0058488c002ea90489e8801d3a7af5ce5f7c05c105bee815c3"}, - {file = "fonttools-4.56.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cad98c94833465bcf28f51c248aaf07ca022efc6a3eba750ad9c1e0256d278"}, - {file = "fonttools-4.56.0-cp313-cp313-win32.whl", hash = "sha256:d0cb73ccf7f6d7ca8d0bc7ea8ac0a5b84969a41c56ac3ac3422a24df2680546f"}, - {file = "fonttools-4.56.0-cp313-cp313-win_amd64.whl", hash = "sha256:62cc1253827d1e500fde9dbe981219fea4eb000fd63402283472d38e7d8aa1c6"}, - {file = "fonttools-4.56.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3fd3fccb7b9adaaecfa79ad51b759f2123e1aba97f857936ce044d4f029abd71"}, - {file = "fonttools-4.56.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:193b86e9f769320bc98ffdb42accafb5d0c8c49bd62884f1c0702bc598b3f0a2"}, - {file = "fonttools-4.56.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e81c1cc80c1d8bf071356cc3e0e25071fbba1c75afc48d41b26048980b3c771"}, - {file = "fonttools-4.56.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9270505a19361e81eecdbc2c251ad1e1a9a9c2ad75fa022ccdee533f55535dc"}, - {file = "fonttools-4.56.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53f5e9767978a4daf46f28e09dbeb7d010319924ae622f7b56174b777258e5ba"}, - {file = "fonttools-4.56.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:9da650cb29bc098b8cfd15ef09009c914b35c7986c8fa9f08b51108b7bc393b4"}, - {file = "fonttools-4.56.0-cp38-cp38-win32.whl", hash = "sha256:965d0209e6dbdb9416100123b6709cb13f5232e2d52d17ed37f9df0cc31e2b35"}, - {file = "fonttools-4.56.0-cp38-cp38-win_amd64.whl", hash = "sha256:654ac4583e2d7c62aebc6fc6a4c6736f078f50300e18aa105d87ce8925cfac31"}, - {file = "fonttools-4.56.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ca7962e8e5fc047cc4e59389959843aafbf7445b6c08c20d883e60ced46370a5"}, - {file = "fonttools-4.56.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1af375734018951c31c0737d04a9d5fd0a353a0253db5fbed2ccd44eac62d8c"}, - {file = "fonttools-4.56.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:442ad4122468d0e47d83bc59d0e91b474593a8c813839e1872e47c7a0cb53b10"}, - {file = "fonttools-4.56.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cf4f8d2a30b454ac682e12c61831dcb174950c406011418e739de592bbf8f76"}, - {file = "fonttools-4.56.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:96a4271f63a615bcb902b9f56de00ea225d6896052c49f20d0c91e9f43529a29"}, - {file = "fonttools-4.56.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c1d38642ca2dddc7ae992ef5d026e5061a84f10ff2b906be5680ab089f55bb8"}, - {file = "fonttools-4.56.0-cp39-cp39-win32.whl", hash = "sha256:2d351275f73ebdd81dd5b09a8b8dac7a30f29a279d41e1c1192aedf1b6dced40"}, - {file = "fonttools-4.56.0-cp39-cp39-win_amd64.whl", hash = "sha256:d6ca96d1b61a707ba01a43318c9c40aaf11a5a568d1e61146fafa6ab20890793"}, - {file = "fonttools-4.56.0-py3-none-any.whl", hash = "sha256:1088182f68c303b50ca4dc0c82d42083d176cba37af1937e1a976a31149d4d14"}, - {file = "fonttools-4.56.0.tar.gz", hash = "sha256:a114d1567e1a1586b7e9e7fc2ff686ca542a82769a296cef131e4c4af51e58f4"}, + {file = "fonttools-4.58.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d500d399aa4e92d969a0d21052696fa762385bb23c3e733703af4a195ad9f34c"}, + {file = "fonttools-4.58.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b00530b84f87792891874938bd42f47af2f7f4c2a1d70466e6eb7166577853ab"}, + {file = "fonttools-4.58.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5579fb3744dfec151b5c29b35857df83e01f06fe446e8c2ebaf1effd7e6cdce"}, + {file = "fonttools-4.58.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf440deecfcc2390998e649156e3bdd0b615863228c484732dc06ac04f57385"}, + {file = "fonttools-4.58.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a81769fc4d473c808310c9ed91fbe01b67f615e3196fb9773e093939f59e6783"}, + {file = "fonttools-4.58.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0162a6a37b0ca70d8505311d541e291cd6cab54d1a986ae3d2686c56c0581e8f"}, + {file = "fonttools-4.58.5-cp310-cp310-win32.whl", hash = "sha256:1cde303422198fdc7f502dbdf1bf65306166cdb9446debd6c7fb826b4d66a530"}, + {file = "fonttools-4.58.5-cp310-cp310-win_amd64.whl", hash = "sha256:75cf8c2812c898dd3d70d62b2b768df4eeb524a83fb987a512ddb3863d6a8c54"}, + {file = "fonttools-4.58.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cda226253bf14c559bc5a17c570d46abd70315c9a687d91c0e01147f87736182"}, + {file = "fonttools-4.58.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a96e4a4e65efd6c098da549ec34f328f08963acd2d7bc910ceba01d2dc73e6"}, + {file = "fonttools-4.58.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d172b92dff59ef8929b4452d5a7b19b8e92081aa87bfb2d82b03b1ff14fc667"}, + {file = "fonttools-4.58.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0bfddfd09aafbbfb3bd98ae67415fbe51eccd614c17db0c8844fe724fbc5d43d"}, + {file = "fonttools-4.58.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cfde5045f1bc92ad11b4b7551807564045a1b38cb037eb3c2bc4e737cd3a8d0f"}, + {file = "fonttools-4.58.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3515ac47a9a5ac025d2899d195198314023d89492340ba86e4ba79451f7518a8"}, + {file = "fonttools-4.58.5-cp311-cp311-win32.whl", hash = "sha256:9f7e2ab9c10b6811b4f12a0768661325a48e664ec0a0530232c1605896a598db"}, + {file = "fonttools-4.58.5-cp311-cp311-win_amd64.whl", hash = "sha256:126c16ec4a672c9cb5c1c255dc438d15436b470afc8e9cac25a2d39dd2dc26eb"}, + {file = "fonttools-4.58.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:c3af3fefaafb570a03051a0d6899b8374dcf8e6a4560e42575843aef33bdbad6"}, + {file = "fonttools-4.58.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:688137789dbd44e8757ad77b49a771539d8069195ffa9a8bcf18176e90bbd86d"}, + {file = "fonttools-4.58.5-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2af65836cf84cd7cb882d0b353bdc73643a497ce23b7414c26499bb8128ca1af"}, + {file = "fonttools-4.58.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d2d79cfeb456bf438cb9fb87437634d4d6f228f27572ca5c5355e58472d5519d"}, + {file = "fonttools-4.58.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0feac9dda9a48a7a342a593f35d50a5cee2dbd27a03a4c4a5192834a4853b204"}, + {file = "fonttools-4.58.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36555230e168511e83ad8637232268649634b8dfff6ef58f46e1ebc057a041ad"}, + {file = "fonttools-4.58.5-cp312-cp312-win32.whl", hash = "sha256:26ec05319353842d127bd02516eacb25b97ca83966e40e9ad6fab85cab0576f4"}, + {file = "fonttools-4.58.5-cp312-cp312-win_amd64.whl", hash = "sha256:778a632e538f82c1920579c0c01566a8f83dc24470c96efbf2fbac698907f569"}, + {file = "fonttools-4.58.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f4b6f1360da13cecc88c0d60716145b31e1015fbe6a59e32f73a4404e2ea92cf"}, + {file = "fonttools-4.58.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4a036822e915692aa2c03e2decc60f49a8190f8111b639c947a4f4e5774d0d7a"}, + {file = "fonttools-4.58.5-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6d7709fcf4577b0f294ee6327088884ca95046e1eccde87c53bbba4d5008541"}, + {file = "fonttools-4.58.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b9b5099ca99b79d6d67162778b1b1616fc0e1de02c1a178248a0da8d78a33852"}, + {file = "fonttools-4.58.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3f2c05a8d82a4d15aebfdb3506e90793aea16e0302cec385134dd960647a36c0"}, + {file = "fonttools-4.58.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79f0c4b1cc63839b61deeac646d8dba46f8ed40332c2ac1b9997281462c2e4ba"}, + {file = "fonttools-4.58.5-cp313-cp313-win32.whl", hash = "sha256:a1a9a2c462760976882131cbab7d63407813413a2d32cd699e86a1ff22bf7aa5"}, + {file = "fonttools-4.58.5-cp313-cp313-win_amd64.whl", hash = "sha256:bca61b14031a4b7dc87e14bf6ca34c275f8e4b9f7a37bc2fe746b532a924cf30"}, + {file = "fonttools-4.58.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:082410bc40014db55be5457836043f0dd1e6b3817c7d11a0aeb44eaa862890af"}, + {file = "fonttools-4.58.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0b0983be58d8c8acb11161fdd3b43d64015cef8c3d65ad9289a252243b236128"}, + {file = "fonttools-4.58.5-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5a0e28fb6abc31ba45a2d11dc2fe826e5a074013d13b7b447b441e8236e5f1c"}, + {file = "fonttools-4.58.5-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d506652abc285934ee949a5f3a952c5d52a09257bc2ba44a92db3ec2804c76fe"}, + {file = "fonttools-4.58.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9e2d71676025dd74a21d682be36d4846aa03644c619f2c2d695a11a7262433f6"}, + {file = "fonttools-4.58.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb46a73759efc8a7eca40203843241cd3c79aa983ed7f7515548ed3d82073761"}, + {file = "fonttools-4.58.5-cp39-cp39-win32.whl", hash = "sha256:bf09f14d73a18c62eb9ad1cac98a37569241ba3cd5789cc578286c128cc29f7f"}, + {file = "fonttools-4.58.5-cp39-cp39-win_amd64.whl", hash = "sha256:8ddb7c0c3e91b187acc1bed31857376926569a18a348ac58d6a71eb8a6b22393"}, + {file = "fonttools-4.58.5-py3-none-any.whl", hash = "sha256:e48a487ed24d9b611c5c4b25db1e50e69e9854ca2670e39a3486ffcd98863ec4"}, + {file = "fonttools-4.58.5.tar.gz", hash = "sha256:b2a35b0a19f1837284b3a23dd64fd7761b8911d50911ecd2bdbaf5b2d1b5df9c"}, ] [package.extras] @@ -1591,14 +1587,14 @@ files = [ [[package]] name = "fsspec" -version = "2025.3.0" +version = "2025.5.1" description = "File-system specification" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "fsspec-2025.3.0-py3-none-any.whl", hash = "sha256:efb87af3efa9103f94ca91a7f8cb7a4df91af9f74fc106c9c7ea0efd7277c1b3"}, - {file = "fsspec-2025.3.0.tar.gz", hash = "sha256:a935fd1ea872591f2b5148907d103488fc523295e6c64b835cfad8c3eca44972"}, + {file = "fsspec-2025.5.1-py3-none-any.whl", hash = "sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462"}, + {file = "fsspec-2025.5.1.tar.gz", hash = "sha256:2e55e47a540b91843b755e83ded97c6e897fa0942b11490113f09e9c443c2475"}, ] [package.extras] @@ -1642,71 +1638,56 @@ files = [ {file = "future-1.0.0.tar.gz", hash = "sha256:bd2968309307861edae1458a4f8a4f3598c03be43b97521076aebf5d94c07b05"}, ] -[[package]] -name = "gdspy" -version = "1.6.13" -description = "Python module for creating/importing/merging GDSII files." -optional = true -python-versions = "*" -groups = ["main"] -markers = "extra == \"dev\" or extra == \"gdspy\"" -files = [ - {file = "gdspy-1.6.13.zip", hash = "sha256:38c61a7267f90767d90b8fcdda96c7a629df26e06f7153084c773f3d6363f4f0"}, -] - -[package.dependencies] -numpy = "*" - [[package]] name = "gdstk" -version = "0.9.59" +version = "0.9.60" description = "Python module for creation and manipulation of GDSII files." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\" or extra == \"gdstk\"" files = [ - {file = "gdstk-0.9.59-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e44317ecfff6cd2fc53fcead1f8958748c78481630212907cbb5f9181c9b79a8"}, - {file = "gdstk-0.9.59-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1ee65575e5ea0d0843b2ab93c9f58f629d40dbfd0d7c7d852d6b09a87db03ae5"}, - {file = "gdstk-0.9.59-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b2a8be8fc0d162c3d37eafe93f11ba28c0afa110a444d3b1cb9401431e93a49f"}, - {file = "gdstk-0.9.59-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb27e4032e0fffc5902bf420f3ade74d31812880c00a6b8067934965ed8cdfa5"}, - {file = "gdstk-0.9.59-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7cd5c8998b29d90a89ef143aa38b59f38ca877e2af25deaab6d122dbed7874a9"}, - {file = "gdstk-0.9.59-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a4834a0fd34ea6f66924f750c25e562c95a0c4a60abad52a2ad35662a40ec9e"}, - {file = "gdstk-0.9.59-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:197af8cccff0cbb7cd12f189baf975ab3e029097bd642b0acede707919f474b1"}, - {file = "gdstk-0.9.59-cp310-cp310-win_amd64.whl", hash = "sha256:966dafb10fad9f50042f0b417c8ba57322d5a534cb5b751fee4acd080058c84f"}, - {file = "gdstk-0.9.59-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:781ff97299691b6a4264ae152a4380f982851de75b72f00173dc297b02f8a4f2"}, - {file = "gdstk-0.9.59-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f972f325478a32b2d522e542ede3d996334023980f57540efafe0bd8bf13a560"}, - {file = "gdstk-0.9.59-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ed576cf1246cba6576530ec8b5384892a3399831fc4ea58103944a1ba687407"}, - {file = "gdstk-0.9.59-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb79af6108413b6dd966318edd65fc1a345a1929d14dd08902a647957318168b"}, - {file = "gdstk-0.9.59-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ee9aa6b76522e7191b940802a865eed4b037a239165cfac51b7ee3a8dd74bbbf"}, - {file = "gdstk-0.9.59-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6900b6554221ca9b9e9df497e9406b1639f0d744176e8a8ef9f941d609826b40"}, - {file = "gdstk-0.9.59-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4892809e9cc9850e4857674d7b61001bfdec8f8d13a5899f18f11bf97b131ebd"}, - {file = "gdstk-0.9.59-cp311-cp311-win_amd64.whl", hash = "sha256:e1b976472d80716af11f1e5905d3583976273a88e9b1345625f31a15f3486969"}, - {file = "gdstk-0.9.59-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b17071ba7ec0ee282b2a9b5fc074fd3b3947c0a067c536c17143366d6d75fe7f"}, - {file = "gdstk-0.9.59-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87884f817ca1beaae8eed3724f4a3906e8fd7420fdc0ffe54997547743044019"}, - {file = "gdstk-0.9.59-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3deae901423007007fe14acfc08d82079d9d0a9f385042f4ed733fdc190d93a1"}, - {file = "gdstk-0.9.59-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df6c468b8a7dab4b26276d063ca131b0583252b0e8575a7adda4fa2d0bd7df59"}, - {file = "gdstk-0.9.59-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:22f50737f8b30bab4c7a518ab83787b503d59eaeb31f4e2e4a9dea5439820304"}, - {file = "gdstk-0.9.59-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:8552459a87ea2855e4cc2c14d0c0db9d79f8c287034970c5c65b0b8e71762db2"}, - {file = "gdstk-0.9.59-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3bc7d1128a1cb237833cace99dfb5f9e1397c368415e6c2f5b402a62e80d7d1c"}, - {file = "gdstk-0.9.59-cp312-cp312-win_amd64.whl", hash = "sha256:de0bdd8c3cabe080d34543633e43f51dbae05394c5439fe584a22d52fd8c3b06"}, - {file = "gdstk-0.9.59-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5438d7ae1277318e407d9537982d192444805be28c82195f106b8dff56be47d2"}, - {file = "gdstk-0.9.59-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2855100a824c30e35cbea746cf5899c367736cd50b0cb722fd5311e388a52670"}, - {file = "gdstk-0.9.59-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f495cdee2299a8b61e127ee52f61ee0181bdd853f48147fe215d99bb9f7db98a"}, - {file = "gdstk-0.9.59-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72896c1725b97c6e437bdbb0c27f6d167953bc32130c1908a8b3e2170d0f28d3"}, - {file = "gdstk-0.9.59-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1ae842ff0e965f0801cb3328a0801b8657f3ca5b3391441b4ac59d15f2d234d9"}, - {file = "gdstk-0.9.59-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:aaa8afbc55c52dec26d11f73a733ac5d3f6bdc1bff1486cab798d209f2571256"}, - {file = "gdstk-0.9.59-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0e5786b6e2543b60bea0fb814accae30b7647af1ba82e50c8c6251579d1ee80b"}, - {file = "gdstk-0.9.59-cp313-cp313-win_amd64.whl", hash = "sha256:53ae9a0604bba68a4babee7730e6e100039cf2188251f0d4a583088a3303950b"}, - {file = "gdstk-0.9.59-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:913b8745d6be27509bfea9f29e0827c237fccdd54ce0dfecc92ccd550c6f619d"}, - {file = "gdstk-0.9.59-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:57a987d24467c28da8283bd028e8a6d3ba69d93dc2ac4a7dec94c8bef0d89576"}, - {file = "gdstk-0.9.59-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:064378d007b4013b447c9f1bbfe55508224dd23fe6572881eb3a468f2bce859b"}, - {file = "gdstk-0.9.59-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aa71eee8a7fea0e9986822569b277ee88846c53a0dab04dd0b381058a4e2144"}, - {file = "gdstk-0.9.59-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:0879616605ca0dc0069e0d028a68630c5a21b6d22149f00d927490278e703a79"}, - {file = "gdstk-0.9.59-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e02e1bd9a97789ce79d240c56889910115ec757e83e2c2005bf8feae8267cfd6"}, - {file = "gdstk-0.9.59-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3c9dc4e789a0a3dc54ac3ebb9bbcdf9e4383c4d61516916b8bd91604c4898c90"}, - {file = "gdstk-0.9.59-cp39-cp39-win_amd64.whl", hash = "sha256:844f70d73282e2f0c77fa0e20c545ffc27c87df144bfbe9f729e8ab142e7d5e3"}, - {file = "gdstk-0.9.59.tar.gz", hash = "sha256:673ba33ac2e758db4a70ffd07808e0af1152132c600be4e390b2ed30520e3462"}, + {file = "gdstk-0.9.60-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:003f265080557aca32622b4a6770e59bacb002c418657b18a2066620c98e0679"}, + {file = "gdstk-0.9.60-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:af46e6f5c8646ad633c569bee6246827c969329eeabc605ba88ddf377f50c489"}, + {file = "gdstk-0.9.60-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75fa27b7bd8975c398b50352162502ff5b5b8c4b64f8ec84c04fa4a2d820bbbe"}, + {file = "gdstk-0.9.60-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16faf1a648881a011769a57e61265e0e6e8c0564f86720a4493a6df339272596"}, + {file = "gdstk-0.9.60-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:98965bc06ea9c81d36cfa3721bb582182f579ed03d6780de89055626b39233f9"}, + {file = "gdstk-0.9.60-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cc4312a6c1dd52c5b2c0edf1ea44766040e4dc617aad5dddb8d1445ce6c17c2e"}, + {file = "gdstk-0.9.60-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3908d8eeb65fefbbaefbad4c9f946ae62ddd5516e73ec11864f24d0f6030deb0"}, + {file = "gdstk-0.9.60-cp310-cp310-win_amd64.whl", hash = "sha256:5f29c6d35d440de8923462e150eb8fb355e38a5b3af79008b4b73c073f9eabb3"}, + {file = "gdstk-0.9.60-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8ab9c85024179ac987133f7681f40565771b19fc689e512d7907a8faf4a6b4be"}, + {file = "gdstk-0.9.60-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b8ed8fdc80962c1a330ba8711094a61dff0304b30f44b9c141b850424290b6a"}, + {file = "gdstk-0.9.60-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aea4dbaf777a8e7cd14f14c8612bf3f15aea76d94451933751fefe8bb63be47"}, + {file = "gdstk-0.9.60-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7f54deea2d9350835eb32d0c6a3c4404d778def9ea68b4d33d2436b760f56dc"}, + {file = "gdstk-0.9.60-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:494492019c3e58c9f112084ca3a2d171e6010f48a4f60b8415cfad97f7918090"}, + {file = "gdstk-0.9.60-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9bb0cd759fc1e10b26b47ae45620f29e36ee492030f3b965ac53ed4a443ed57f"}, + {file = "gdstk-0.9.60-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:807594d81677e7865e3d63692a6faeb27d09e4206b542315a0779b69cde47182"}, + {file = "gdstk-0.9.60-cp311-cp311-win_amd64.whl", hash = "sha256:56b6706f598601be17c8f9fecf8adc9649cbe6bfd3da5e389018d96369996630"}, + {file = "gdstk-0.9.60-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:724054622a6afff52bd6863d88e09053b13f8e015c874d81a7de6f0d37a88df2"}, + {file = "gdstk-0.9.60-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8ce17b51e6f6494e038224033f55c4f8226897e3505ad5d7e0c37a7aadbf2e81"}, + {file = "gdstk-0.9.60-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5c525fd1b4c9a56df3aa55646be1980e3edcc326485ca2058b889f63fd9d265f"}, + {file = "gdstk-0.9.60-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9155d90b3035140201519f4ab97af6ec7ac96fa2cc4ca2927b93e5877c458315"}, + {file = "gdstk-0.9.60-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a51d0561f76059db7cfd6396163e10b3c89c2dd8285a38ef940f374caeac38a5"}, + {file = "gdstk-0.9.60-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7702cec46ab36b3cc6f08db29e7fb20cc93946a2cf3fa01188b0b6a831d83cdf"}, + {file = "gdstk-0.9.60-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce367af239b4cf07e305cdd682e3a84df56e26c3ddbc4b1f55bc91467363386b"}, + {file = "gdstk-0.9.60-cp312-cp312-win_amd64.whl", hash = "sha256:a94f259a453736f24d4a98f8fca857f082081f84051094ad6b2d0f1b81fee19d"}, + {file = "gdstk-0.9.60-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5f1832f90f23c761e182e8f0dffcf9e47260f6be47a445b5027cd17ff9b2d51b"}, + {file = "gdstk-0.9.60-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:db240ecabacf0063e035d7ad7e156a500d895c0b9886d0b2adaa9681b83d9424"}, + {file = "gdstk-0.9.60-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9c80eed22802b72566a89e4d429b1ec820a1b28658bc20830f455933d5ed963"}, + {file = "gdstk-0.9.60-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0a35625a965848aabf52b4e92c37e0876bdc6f01099f0614fc97dfb28676e19"}, + {file = "gdstk-0.9.60-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bc52f232471b97e52004b047e4300de9e92575e62fbf40fe6bd1d4fbb1b87bc4"}, + {file = "gdstk-0.9.60-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:aa0a7a617f90bd2c4ab5b5032638ea01c39f3305490bda67a82d8310e266aeb4"}, + {file = "gdstk-0.9.60-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64249dfc5803e987decbae5bc28144242f0297869fca1074b26380f261998ee6"}, + {file = "gdstk-0.9.60-cp313-cp313-win_amd64.whl", hash = "sha256:9e41b38a719991b1e36ea0320c44688ac18e64ae53d9e5775fc7222fccfbb34a"}, + {file = "gdstk-0.9.60-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:218beba49fe8edd398c84c0d150d2e5d0ed3d9a67f74e15d3f378e717136dc93"}, + {file = "gdstk-0.9.60-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2365146721c6887e4d0b9bc30d94cf2f5a85b16dfa736431740cf329a1bd81f"}, + {file = "gdstk-0.9.60-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17ac4e85a159ef181a6aaa38131e14bca34f9a2b437f94a41f15a441179db648"}, + {file = "gdstk-0.9.60-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c796b0dc3d18075ee5f12e02509e696572469d21bd368d3f6abe1c5d93b27ce7"}, + {file = "gdstk-0.9.60-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1532f499a0bf2874e9d3bf641cd43740525cc3b8b75f143024850fecf8ffe1e3"}, + {file = "gdstk-0.9.60-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:26a8750297a9fd69c55ee9bb97310558569885ad660a311f850e7ded46691dc7"}, + {file = "gdstk-0.9.60-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2a03453d5942036ebae3276d12bbe263ead90dc6af00072ed251431e37effe99"}, + {file = "gdstk-0.9.60-cp39-cp39-win_amd64.whl", hash = "sha256:9bd4264e0057c7d99a9b1519b72d47cabd314af1dc2228246c723e9962a89d60"}, + {file = "gdstk-0.9.60.tar.gz", hash = "sha256:6d9b807bf0ea43903779c0ba8c65b4fdfbca903a90dbb1acfd11b41fd0574588"}, ] [package.dependencies] @@ -1771,15 +1752,15 @@ numpy = "*" [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] @@ -1800,38 +1781,38 @@ packaging = "*" [[package]] name = "h5py" -version = "3.13.0" +version = "3.14.0" description = "Read and write HDF5 files from Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "h5py-3.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5540daee2b236d9569c950b417f13fd112d51d78b4c43012de05774908dff3f5"}, - {file = "h5py-3.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:10894c55d46df502d82a7a4ed38f9c3fdbcb93efb42e25d275193e093071fade"}, - {file = "h5py-3.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb267ce4b83f9c42560e9ff4d30f60f7ae492eacf9c7ede849edf8c1b860e16b"}, - {file = "h5py-3.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2cf6a231a07c14acd504a945a6e9ec115e0007f675bde5e0de30a4dc8d86a31"}, - {file = "h5py-3.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:851ae3a8563d87a5a0dc49c2e2529c75b8842582ccaefbf84297d2cfceeacd61"}, - {file = "h5py-3.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8a8e38ef4ceb969f832cc230c0cf808c613cc47e31e768fd7b1106c55afa1cb8"}, - {file = "h5py-3.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f35640e81b03c02a88b8bf99fb6a9d3023cc52f7c627694db2f379e0028f2868"}, - {file = "h5py-3.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:337af114616f3656da0c83b68fcf53ecd9ce9989a700b0883a6e7c483c3235d4"}, - {file = "h5py-3.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:782ff0ac39f455f21fd1c8ebc007328f65f43d56718a89327eec76677ebf238a"}, - {file = "h5py-3.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:22ffe2a25770a2d67213a1b94f58006c14dce06933a42d2aaa0318c5868d1508"}, - {file = "h5py-3.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:477c58307b6b9a2509c59c57811afb9f598aedede24a67da808262dfa0ee37b4"}, - {file = "h5py-3.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:57c4c74f627c616f02b7aec608a8c706fe08cb5b0ba7c08555a4eb1dde20805a"}, - {file = "h5py-3.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:357e6dc20b101a805ccfd0024731fbaf6e8718c18c09baf3b5e4e9d198d13fca"}, - {file = "h5py-3.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6f13f9b5ce549448c01e4dfe08ea8d1772e6078799af2c1c8d09e941230a90d"}, - {file = "h5py-3.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:21daf38171753899b5905f3d82c99b0b1ec2cbbe282a037cad431feb620e62ec"}, - {file = "h5py-3.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e520ec76de00943dd017c8ea3f354fa1d2f542eac994811943a8faedf2a7d5cb"}, - {file = "h5py-3.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e79d8368cd9295045956bfb436656bea3f915beaa11d342e9f79f129f5178763"}, - {file = "h5py-3.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56dd172d862e850823c4af02dc4ddbc308f042b85472ffdaca67f1598dff4a57"}, - {file = "h5py-3.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be949b46b7388074c5acae017fbbe3e5ba303fd9daaa52157fdfef30bbdacadd"}, - {file = "h5py-3.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:4f97ecde7ac6513b21cd95efdfc38dc6d19f96f6ca6f2a30550e94e551458e0a"}, - {file = "h5py-3.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82690e89c72b85addf4fc4d5058fb1e387b6c14eb063b0b879bf3f42c3b93c35"}, - {file = "h5py-3.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d571644958c5e19a61c793d8d23cd02479572da828e333498c9acc463f4a3997"}, - {file = "h5py-3.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:560e71220dc92dfa254b10a4dcb12d56b574d2d87e095db20466b32a93fec3f9"}, - {file = "h5py-3.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c10f061764d8dce0a9592ce08bfd5f243a00703325c388f1086037e5d619c5f1"}, - {file = "h5py-3.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:9c82ece71ed1c2b807b6628e3933bc6eae57ea21dac207dca3470e3ceaaf437c"}, - {file = "h5py-3.13.0.tar.gz", hash = "sha256:1870e46518720023da85d0895a1960ff2ce398c5671eac3b1a41ec696b7105c3"}, + {file = "h5py-3.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:24df6b2622f426857bda88683b16630014588a0e4155cba44e872eb011c4eaed"}, + {file = "h5py-3.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ff2389961ee5872de697054dd5a033b04284afc3fb52dc51d94561ece2c10c6"}, + {file = "h5py-3.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:016e89d3be4c44f8d5e115fab60548e518ecd9efe9fa5c5324505a90773e6f03"}, + {file = "h5py-3.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1223b902ef0b5d90bcc8a4778218d6d6cd0f5561861611eda59fa6c52b922f4d"}, + {file = "h5py-3.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:852b81f71df4bb9e27d407b43071d1da330d6a7094a588efa50ef02553fa7ce4"}, + {file = "h5py-3.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f30dbc58f2a0efeec6c8836c97f6c94afd769023f44e2bb0ed7b17a16ec46088"}, + {file = "h5py-3.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:543877d7f3d8f8a9828ed5df6a0b78ca3d8846244b9702e99ed0d53610b583a8"}, + {file = "h5py-3.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c497600c0496548810047257e36360ff551df8b59156d3a4181072eed47d8ad"}, + {file = "h5py-3.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:723a40ee6505bd354bfd26385f2dae7bbfa87655f4e61bab175a49d72ebfc06b"}, + {file = "h5py-3.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:d2744b520440a996f2dae97f901caa8a953afc055db4673a993f2d87d7f38713"}, + {file = "h5py-3.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e0045115d83272090b0717c555a31398c2c089b87d212ceba800d3dc5d952e23"}, + {file = "h5py-3.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6da62509b7e1d71a7d110478aa25d245dd32c8d9a1daee9d2a42dba8717b047a"}, + {file = "h5py-3.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554ef0ced3571366d4d383427c00c966c360e178b5fb5ee5bb31a435c424db0c"}, + {file = "h5py-3.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cbd41f4e3761f150aa5b662df991868ca533872c95467216f2bec5fcad84882"}, + {file = "h5py-3.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:bf4897d67e613ecf5bdfbdab39a1158a64df105827da70ea1d90243d796d367f"}, + {file = "h5py-3.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:aa4b7bbce683379b7bf80aaba68e17e23396100336a8d500206520052be2f812"}, + {file = "h5py-3.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9603a501a04fcd0ba28dd8f0995303d26a77a980a1f9474b3417543d4c6174"}, + {file = "h5py-3.14.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8cbaf6910fa3983c46172666b0b8da7b7bd90d764399ca983236f2400436eeb"}, + {file = "h5py-3.14.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d90e6445ab7c146d7f7981b11895d70bc1dd91278a4f9f9028bc0c95e4a53f13"}, + {file = "h5py-3.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:ae18e3de237a7a830adb76aaa68ad438d85fe6e19e0d99944a3ce46b772c69b3"}, + {file = "h5py-3.14.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5cc1601e78027cedfec6dd50efb4802f018551754191aeb58d948bd3ec3bd7a"}, + {file = "h5py-3.14.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e59d2136a8b302afd25acdf7a89b634e0eb7c66b1a211ef2d0457853768a2ef"}, + {file = "h5py-3.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:573c33ad056ac7c1ab6d567b6db9df3ffc401045e3f605736218f96c1e0490c6"}, + {file = "h5py-3.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccbe17dc187c0c64178f1a10aa274ed3a57d055117588942b8a08793cc448216"}, + {file = "h5py-3.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f025cf30ae738c4c4e38c7439a761a71ccfcce04c2b87b2a2ac64e8c5171d43"}, + {file = "h5py-3.14.0.tar.gz", hash = "sha256:2372116b2e0d5d3e5e705b7f663f7c8d96fa79a4052d250484ef91d24d6a08f4"}, ] [package.dependencies] @@ -1839,20 +1820,20 @@ numpy = ">=1.19.3" [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] @@ -1888,14 +1869,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "humanize" -version = "4.12.1" +version = "4.12.3" description = "Python humanize utilities" optional = true python-versions = ">=3.9" groups = ["main"] files = [ - {file = "humanize-4.12.1-py3-none-any.whl", hash = "sha256:86014ca5c52675dffa1d404491952f1f5bf03b07c175a51891a343daebf01fea"}, - {file = "humanize-4.12.1.tar.gz", hash = "sha256:1338ba97415c96556758a6e2f65977ed406dddf4620d4c6db9bbdfd07f0f1232"}, + {file = "humanize-4.12.3-py3-none-any.whl", hash = "sha256:2cbf6370af06568fa6d2da77c86edb7886f3160ecd19ee1ffef07979efc597f6"}, + {file = "humanize-4.12.3.tar.gz", hash = "sha256:8430be3a615106fdfceb0b2c1b41c4c98c6b0fc5cc59663a5539b111dd325fb0"}, ] [package.extras] @@ -1903,15 +1884,15 @@ tests = ["freezegun", "pytest", "pytest-cov"] [[package]] name = "identify" -version = "2.6.9" +version = "2.6.12" description = "File identification library for Python" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "identify-2.6.9-py2.py3-none-any.whl", hash = "sha256:c98b4322da415a8e5a70ff6e51fbc2d2932c015532d77e9f8537b4ba7813b150"}, - {file = "identify-2.6.9.tar.gz", hash = "sha256:d40dfe3142a1421d8518e3d3985ef5ac42890683e32306ad614a29490abeb6bf"}, + {file = "identify-2.6.12-py2.py3-none-any.whl", hash = "sha256:ad9672d5a72e0d2ff7c5c8809b62dfa60458626352fb0eb7b55e69bdc45334a2"}, + {file = "identify-2.6.12.tar.gz", hash = "sha256:d8de45749f1efb108badef65ee8386f0f7bb19a7f26185f74de6367bffbaf0e6"}, ] [package.extras] @@ -1947,14 +1928,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.6.1" +version = "8.7.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, - {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, ] [package.dependencies] @@ -1973,7 +1954,7 @@ type = ["pytest-mypy"] name = "importlib-resources" version = "6.5.2" description = "Read resources from Python packages" -optional = true +optional = false python-versions = ">=3.9" groups = ["main"] files = [ @@ -2081,15 +2062,15 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa [[package]] name = "ipython" -version = "8.34.0" +version = "8.37.0" description = "IPython: Productive Interactive Computing" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version == \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "ipython-8.34.0-py3-none-any.whl", hash = "sha256:0419883fa46e0baa182c5d50ebb8d6b49df1889fdb70750ad6d8cfe678eda6e3"}, - {file = "ipython-8.34.0.tar.gz", hash = "sha256:c31d658e754673ecc6514583e7dda8069e47136eb62458816b7d1e6625948b5a"}, + {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, + {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, ] [package.dependencies] @@ -2117,19 +2098,19 @@ notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] name = "ipython" -version = "9.0.2" +version = "9.4.0" description = "IPython: Productive Interactive Computing" optional = true python-versions = ">=3.11" groups = ["main"] markers = "python_version >= \"3.11\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "ipython-9.0.2-py3-none-any.whl", hash = "sha256:143ef3ea6fb1e1bffb4c74b114051de653ffb7737a3f7ab1670e657ca6ae8c44"}, - {file = "ipython-9.0.2.tar.gz", hash = "sha256:ec7b479e3e5656bf4f58c652c120494df1820f4f28f522fb7ca09e213c2aab52"}, + {file = "ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066"}, + {file = "ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270"}, ] [package.dependencies] @@ -2151,7 +2132,7 @@ black = ["black"] doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinx_toml (==0.0.4)", "typing_extensions"] matplotlib = ["matplotlib"] test = ["packaging", "pytest", "pytest-asyncio (<0.22)", "testpath"] -test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] +test-extra = ["curio", "ipykernel", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbclient", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] name = "ipython-pygments-lexers" @@ -2171,23 +2152,23 @@ pygments = "*" [[package]] name = "ipywidgets" -version = "8.1.5" +version = "8.1.7" description = "Jupyter interactive widgets" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245"}, - {file = "ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17"}, + {file = "ipywidgets-8.1.7-py3-none-any.whl", hash = "sha256:764f2602d25471c213919b8a1997df04bef869251db4ca8efba1b76b1bd9f7bb"}, + {file = "ipywidgets-8.1.7.tar.gz", hash = "sha256:15f1ac050b9ccbefd45dccfbb2ef6bed0029d8278682d569d71b8dd96bee0376"}, ] [package.dependencies] comm = ">=0.1.3" ipython = ">=6.1.0" -jupyterlab-widgets = ">=3.0.12,<3.1.0" +jupyterlab_widgets = ">=3.0.15,<3.1.0" traitlets = ">=4.3.1" -widgetsnbextension = ">=4.0.12,<4.1.0" +widgetsnbextension = ">=4.0.14,<4.1.0" [package.extras] test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] @@ -2277,8 +2258,8 @@ files = [ jaxlib = "0.5.3" ml_dtypes = ">=0.4.0" numpy = [ - {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.25"}, + {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, ] opt_einsum = "*" scipy = ">=1.11.1" @@ -2395,22 +2376,22 @@ typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [[package]] name = "jaxtyping" -version = "0.3.0" +version = "0.3.2" description = "Type annotations and runtime checking for shape and dtype of JAX/NumPy/PyTorch/etc. arrays." optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "jaxtyping-0.3.0-py3-none-any.whl", hash = "sha256:4b20d4e7c94d6a2850d78d7849cf33e38a87b993f2f78977d8093efb42cdb892"}, - {file = "jaxtyping-0.3.0.tar.gz", hash = "sha256:b334b56436295332addd0b6c451548404d3700c9c35c7fa877c6b3b30ea968de"}, + {file = "jaxtyping-0.3.2-py3-none-any.whl", hash = "sha256:6a020fd276226ddb5ac4f5725323843dd65e3c7e85c64fd62431e5f738c74e04"}, + {file = "jaxtyping-0.3.2.tar.gz", hash = "sha256:f30483fac4b42e915db8ad2414a85c3b63284aa7d3c100b96b59f755cf4a86ad"}, ] [package.dependencies] wadler-lindig = ">=0.1.3" [package.extras] -docs = ["hippogriffe (==0.1.0)", "mkdocs (==1.6.1)", "mkdocs-include-exclude-files (==0.1.0)", "mkdocs-ipynb (==0.1.0)", "mkdocs-material (==9.6.7)", "mkdocstrings[python] (==0.28.3)", "pymdown-extensions (==10.14.3)"] +docs = ["hippogriffe (==0.2.0)", "mkdocs (==1.6.1)", "mkdocs-include-exclude-files (==0.1.0)", "mkdocs-ipynb (==0.1.0)", "mkdocs-material (==9.6.7)", "mkdocstrings[python] (==0.28.3)", "pymdown-extensions (==10.14.3)"] [[package]] name = "jedi" @@ -2466,31 +2447,31 @@ files = [ [[package]] name = "joblib" -version = "1.4.2" +version = "1.5.1" description = "Lightweight pipelining with Python functions" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6"}, - {file = "joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e"}, + {file = "joblib-1.5.1-py3-none-any.whl", hash = "sha256:4719a31f054c7d766948dcd83e9613686b27114f190f717cec7eaa2084f8a74a"}, + {file = "joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444"}, ] [[package]] name = "json5" -version = "0.10.0" +version = "0.12.0" description = "A Python implementation of the JSON5 data format." optional = true python-versions = ">=3.8.0" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa"}, - {file = "json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559"}, + {file = "json5-0.12.0-py3-none-any.whl", hash = "sha256:6d37aa6c08b0609f16e1ec5ff94697e2cbbfbad5ac112afa05794da9ab7810db"}, + {file = "json5-0.12.0.tar.gz", hash = "sha256:0b4b6ff56801a1c7dc817b0241bca4ce474a0e6a163bfef3fc594d3fd263ff3a"}, ] [package.extras] -dev = ["build (==1.2.2.post1)", "coverage (==7.5.3)", "mypy (==1.13.0)", "pip (==24.3.1)", "pylint (==3.2.3)", "ruff (==0.7.3)", "twine (==5.1.1)", "uv (==0.5.1)"] +dev = ["build (==1.2.2.post1)", "coverage (==7.5.4) ; python_version < \"3.9\"", "coverage (==7.8.0) ; python_version >= \"3.9\"", "mypy (==1.14.1) ; python_version < \"3.9\"", "mypy (==1.15.0) ; python_version >= \"3.9\"", "pip (==25.0.1)", "pylint (==3.2.7) ; python_version < \"3.9\"", "pylint (==3.3.6) ; python_version >= \"3.9\"", "ruff (==0.11.2)", "twine (==6.1.0)", "uv (==0.6.11)"] [[package]] name = "jsonpointer" @@ -2507,15 +2488,15 @@ files = [ [[package]] name = "jsonschema" -version = "4.23.0" +version = "4.24.0" description = "An implementation of JSON Schema validation for Python" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566"}, - {file = "jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4"}, + {file = "jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"}, + {file = "jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196"}, ] [package.dependencies] @@ -2538,15 +2519,15 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2024.10.1" +version = "2025.4.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, - {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, + {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"}, + {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"}, ] [package.dependencies] @@ -2626,15 +2607,15 @@ test = ["flaky", "pexpect", "pytest"] [[package]] name = "jupyter-core" -version = "5.7.2" +version = "5.8.1" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, - {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, + {file = "jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0"}, + {file = "jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941"}, ] [package.dependencies] @@ -2643,8 +2624,8 @@ pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_ traitlets = ">=5.3" [package.extras] -docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] -test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] +docs = ["intersphinx-registry", "myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest (<9)", "pytest-cov", "pytest-timeout"] [[package]] name = "jupyter-events" @@ -2693,15 +2674,15 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.15.0" +version = "2.16.0" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3"}, - {file = "jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084"}, + {file = "jupyter_server-2.16.0-py3-none-any.whl", hash = "sha256:3d8db5be3bc64403b1c65b400a1d7f4647a5ce743f3b20dbdefe8ddb7b55af9e"}, + {file = "jupyter_server-2.16.0.tar.gz", hash = "sha256:65d4b44fdf2dcbbdfe0aa1ace4a842d4aaf746a2b7b168134d5aaed35621b7f6"}, ] [package.dependencies] @@ -2771,15 +2752,15 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.3.6" +version = "4.4.4" description = "JupyterLab computational environment" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jupyterlab-4.3.6-py3-none-any.whl", hash = "sha256:fc9eb0455562a56a9bd6d2977cf090842f321fa1a298fcee9bf8c19de353d5fd"}, - {file = "jupyterlab-4.3.6.tar.gz", hash = "sha256:2900ffdbfca9ed37c4ad7fdda3eb76582fd945d46962af3ac64741ae2d6b2ff4"}, + {file = "jupyterlab-4.4.4-py3-none-any.whl", hash = "sha256:711611e4f59851152eb93316c3547c3ec6291f16bb455f1f4fa380d25637e0dd"}, + {file = "jupyterlab-4.4.4.tar.gz", hash = "sha256:163fee1ef702e0a057f75d2eed3ed1da8a986d59eb002cbeb6f0c2779e6cd153"}, ] [package.dependencies] @@ -2794,15 +2775,15 @@ jupyter-server = ">=2.4.0,<3" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2" packaging = "*" -setuptools = ">=40.8.0" +setuptools = ">=41.1.0" tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} tornado = ">=6.2.0" traitlets = "*" [package.extras] -dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.6.9)"] -docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<8.1.0)", "sphinx-copybutton"] -docs-screenshots = ["altair (==5.4.1)", "ipython (==8.16.1)", "ipywidgets (==8.1.5)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.2.post3)", "matplotlib (==3.9.2)", "nbconvert (>=7.0.0)", "pandas (==2.2.3)", "scipy (==1.14.1)", "vega-datasets (==0.9.0)"] +dev = ["build", "bump2version", "coverage", "hatch", "pre-commit", "pytest-cov", "ruff (==0.11.4)"] +docs = ["jsx-lexer", "myst-parser", "pydata-sphinx-theme (>=0.13.0)", "pytest", "pytest-check-links", "pytest-jupyter", "sphinx (>=1.8,<8.2.0)", "sphinx-copybutton"] +docs-screenshots = ["altair (==5.5.0)", "ipython (==8.16.1)", "ipywidgets (==8.1.5)", "jupyterlab-geojson (==3.4.0)", "jupyterlab-language-pack-zh-cn (==4.3.post1)", "matplotlib (==3.10.0)", "nbconvert (>=7.0.0)", "pandas (==2.2.3)", "scipy (==1.15.1)", "vega-datasets (==0.9.0)"] test = ["coverage", "pytest (>=7.0)", "pytest-check-links (>=0.7)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter (>=0.5.3)", "pytest-timeout", "pytest-tornasync", "requests", "requests-cache", "virtualenv"] upgrade-extension = ["copier (>=9,<10)", "jinja2-time (<0.3)", "pydantic (<3.0)", "pyyaml-include (<3.0)", "tomli-w (<2.0)"] @@ -2849,15 +2830,15 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v [[package]] name = "jupyterlab-widgets" -version = "3.0.13" +version = "3.0.15" description = "Jupyter interactive widgets for JupyterLab" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54"}, - {file = "jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed"}, + {file = "jupyterlab_widgets-3.0.15-py3-none-any.whl", hash = "sha256:d59023d7d7ef71400d51e6fee9a88867f6e65e10a4201605d2d7f3e8f012a31c"}, + {file = "jupyterlab_widgets-3.0.15.tar.gz", hash = "sha256:2920888a0c2922351a9202817957a68c07d99673504d6cd37345299e971bb08b"}, ] [[package]] @@ -3118,25 +3099,33 @@ pybind11 = "*" [[package]] name = "klujax" -version = "0.4.1" +version = "0.4.3" description = "a KLU solver for JAX" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "klujax-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9a415b32c378dcaa23f2f45e13796a740285d61a0414f3542965121a84f2a9c2"}, - {file = "klujax-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703ec664340efa58e90cca5a048d71d0b080c1c3b6a76e2e2625ee29e8095e68"}, - {file = "klujax-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:95e99fcdf4a9706973bc04bbbee84283e27f70bebf3859ded621b81758c1df41"}, - {file = "klujax-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:32b0dcacaca3609b032c082ff53e15812e174bb663e07fd2955a731d471ba87d"}, - {file = "klujax-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b43a6975d85c6fa866f00d45498b40c38ece5aaac670b1698cd6ffec5040e5"}, - {file = "klujax-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5021291ee866209adda01bca8ca417ecd789b0c8673746ee1d02498ee6c61d57"}, - {file = "klujax-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b1d2da1745e45711fa9aa4e1348eb1a2a4f22586cff0890052180c0c6a45c60"}, - {file = "klujax-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cf1dcca3c2d15f5ee62d7bbb755788321a91d5e0e000aeebf0edf1aa4167b74"}, - {file = "klujax-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:feb52cf1d932c4af2ceda1d1c56bbfd59e1b5e12697d7f3c8386d424cc5590ba"}, - {file = "klujax-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e1a446db0cf70e754bb99f157dca64523fb6d822a0db649af028fff5d15ac39c"}, - {file = "klujax-0.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd85152975282f9e85c38fd6cc16c4da23562bff166c2e8c75a9b473a47d9429"}, - {file = "klujax-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:29aef61fec1fb427cc6a16cf09b63c06ba676c590aa1ea76ff90c768c1037209"}, + {file = "klujax-0.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:26127b2f76f76d76e26bd20ea516e3b42cab020b6eeafc7bdb17c1e9258b11e1"}, + {file = "klujax-0.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e5cd54acdd452407343d52076aa54cf33538ef7a3c57a66643d5a9d90b1c75"}, + {file = "klujax-0.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93c820ae1d02fa8b5b23aba7242087b7557dbc6b1478689d515ce4ab793e28f8"}, + {file = "klujax-0.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee565eb8817466e0ca3f29f94856769cd083ecd402f2f95e839e74dee15dda44"}, + {file = "klujax-0.4.3-cp310-cp310-win_arm64.whl", hash = "sha256:0d25e5c57ea6d5eeb9d786f705bc2ecf9db5853a0740dbda2aa47bac5d80af7c"}, + {file = "klujax-0.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c24eefef349a8d570a04a05a861499b7a7ed87ae2a537dac7f1744ab70dd2668"}, + {file = "klujax-0.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ec6177494088e6ee27bfead210f1ad67fa6e6291eb9a259cdddf01a924d30e6"}, + {file = "klujax-0.4.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fe85fc53eb12dfd235e64f9b61a6db03e03e24217ec8eb955dda7875d97b0bc"}, + {file = "klujax-0.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:8799b6052f0da01382509fcf66e2e14bd24e11f3b498cc6acf15cd7752dc1c9b"}, + {file = "klujax-0.4.3-cp311-cp311-win_arm64.whl", hash = "sha256:54f2003f1eb662a8c8b632d014325dfdfb550d6c586634397ad871d4a2bd59c9"}, + {file = "klujax-0.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fdf21636f4ceba4ebdb8337db8115099a9c8e85f7821015f4a869d608387ac2c"}, + {file = "klujax-0.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd76ecfbe3776298b2c637839c207bcad7993a3e5c039208b8a697350759a15"}, + {file = "klujax-0.4.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7a9e26d38adeaea658cbe844d7ac60fc8c6716b141d11c2ec43f65a976e15"}, + {file = "klujax-0.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:c7ab718933402dc4a4a58c3e10e3713d2e69626c6f20e67c495ada363a9fe171"}, + {file = "klujax-0.4.3-cp312-cp312-win_arm64.whl", hash = "sha256:77e3a9c950d25ba7bdb767895b448457848a7e3a81ae9992622c544d012fbfc0"}, + {file = "klujax-0.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:36fbf836b92044aad9630072d5d84e655f1445c52992941873732f3ff9c3a3be"}, + {file = "klujax-0.4.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8baeeefab615123dad4e13c3919354bf1da3c540a69f4440a86b6725950e752f"}, + {file = "klujax-0.4.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5fd7440b986bbfce7b65412af27066e3e186daf05be14452e5fe9e52bb32116"}, + {file = "klujax-0.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:26d82f832315753c20183d3ef1c37c0c3b3dedc6f0b68dabed1a13fe19ee5d1b"}, + {file = "klujax-0.4.3-cp313-cp313-win_arm64.whl", hash = "sha256:cfe42f846f582a198442d7c4d882c7ca6c4f3f6af7891e54628aa035c8c744cc"}, ] [package.dependencies] @@ -3326,47 +3315,47 @@ dev = ["meson-python (>=0.13.1,<0.17.0)", "numpy (>=1.25)", "pybind11 (>=2.6,!=2 [[package]] name = "matplotlib" -version = "3.10.1" +version = "3.10.3" description = "Python plotting package" optional = false python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "matplotlib-3.10.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16"}, - {file = "matplotlib-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2"}, - {file = "matplotlib-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698"}, - {file = "matplotlib-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19"}, - {file = "matplotlib-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044"}, - {file = "matplotlib-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f"}, - {file = "matplotlib-3.10.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401"}, - {file = "matplotlib-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe"}, - {file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd"}, - {file = "matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c"}, - {file = "matplotlib-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7"}, - {file = "matplotlib-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a"}, - {file = "matplotlib-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107"}, - {file = "matplotlib-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be"}, - {file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6"}, - {file = "matplotlib-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d"}, - {file = "matplotlib-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea"}, - {file = "matplotlib-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c"}, - {file = "matplotlib-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b"}, - {file = "matplotlib-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1"}, - {file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3"}, - {file = "matplotlib-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6"}, - {file = "matplotlib-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b"}, - {file = "matplotlib-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473"}, - {file = "matplotlib-3.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01"}, - {file = "matplotlib-3.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb"}, - {file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972"}, - {file = "matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3"}, - {file = "matplotlib-3.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f"}, - {file = "matplotlib-3.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9"}, - {file = "matplotlib-3.10.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc"}, - {file = "matplotlib-3.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4"}, - {file = "matplotlib-3.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779"}, - {file = "matplotlib-3.10.1.tar.gz", hash = "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba"}, + {file = "matplotlib-3.10.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:213fadd6348d106ca7db99e113f1bea1e65e383c3ba76e8556ba4a3054b65ae7"}, + {file = "matplotlib-3.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3bec61cb8221f0ca6313889308326e7bb303d0d302c5cc9e523b2f2e6c73deb"}, + {file = "matplotlib-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c21ae75651c0231b3ba014b6d5e08fb969c40cdb5a011e33e99ed0c9ea86ecb"}, + {file = "matplotlib-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a49e39755580b08e30e3620efc659330eac5d6534ab7eae50fa5e31f53ee4e30"}, + {file = "matplotlib-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cf4636203e1190871d3a73664dea03d26fb019b66692cbfd642faafdad6208e8"}, + {file = "matplotlib-3.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:fd5641a9bb9d55f4dd2afe897a53b537c834b9012684c8444cc105895c8c16fd"}, + {file = "matplotlib-3.10.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0ef061f74cd488586f552d0c336b2f078d43bc00dc473d2c3e7bfee2272f3fa8"}, + {file = "matplotlib-3.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96985d14dc5f4a736bbea4b9de9afaa735f8a0fc2ca75be2fa9e96b2097369d"}, + {file = "matplotlib-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5f0283da91e9522bdba4d6583ed9d5521566f63729ffb68334f86d0bb98049"}, + {file = "matplotlib-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdfa07c0ec58035242bc8b2c8aae37037c9a886370eef6850703d7583e19964b"}, + {file = "matplotlib-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c0b9849a17bce080a16ebcb80a7b714b5677d0ec32161a2cc0a8e5a6030ae220"}, + {file = "matplotlib-3.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:eef6ed6c03717083bc6d69c2d7ee8624205c29a8e6ea5a31cd3492ecdbaee1e1"}, + {file = "matplotlib-3.10.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0ab1affc11d1f495ab9e6362b8174a25afc19c081ba5b0775ef00533a4236eea"}, + {file = "matplotlib-3.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a818d8bdcafa7ed2eed74487fdb071c09c1ae24152d403952adad11fa3c65b4"}, + {file = "matplotlib-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748ebc3470c253e770b17d8b0557f0aa85cf8c63fd52f1a61af5b27ec0b7ffee"}, + {file = "matplotlib-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed70453fd99733293ace1aec568255bc51c6361cb0da94fa5ebf0649fdb2150a"}, + {file = "matplotlib-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbed9917b44070e55640bd13419de83b4c918e52d97561544814ba463811cbc7"}, + {file = "matplotlib-3.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:cf37d8c6ef1a48829443e8ba5227b44236d7fcaf7647caa3178a4ff9f7a5be05"}, + {file = "matplotlib-3.10.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9f2efccc8dcf2b86fc4ee849eea5dcaecedd0773b30f47980dc0cbeabf26ec84"}, + {file = "matplotlib-3.10.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3ddbba06a6c126e3301c3d272a99dcbe7f6c24c14024e80307ff03791a5f294e"}, + {file = "matplotlib-3.10.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:748302b33ae9326995b238f606e9ed840bf5886ebafcb233775d946aa8107a15"}, + {file = "matplotlib-3.10.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a80fcccbef63302c0efd78042ea3c2436104c5b1a4d3ae20f864593696364ac7"}, + {file = "matplotlib-3.10.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55e46cbfe1f8586adb34f7587c3e4f7dedc59d5226719faf6cb54fc24f2fd52d"}, + {file = "matplotlib-3.10.3-cp313-cp313-win_amd64.whl", hash = "sha256:151d89cb8d33cb23345cd12490c76fd5d18a56581a16d950b48c6ff19bb2ab93"}, + {file = "matplotlib-3.10.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c26dd9834e74d164d06433dc7be5d75a1e9890b926b3e57e74fa446e1a62c3e2"}, + {file = "matplotlib-3.10.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:24853dad5b8c84c8c2390fc31ce4858b6df504156893292ce8092d190ef8151d"}, + {file = "matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f7878214d369d7d4215e2a9075fef743be38fa401d32e6020bab2dfabaa566"}, + {file = "matplotlib-3.10.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6929fc618cb6db9cb75086f73b3219bbb25920cb24cee2ea7a12b04971a4158"}, + {file = "matplotlib-3.10.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c7818292a5cc372a2dc4c795e5c356942eb8350b98ef913f7fda51fe175ac5d"}, + {file = "matplotlib-3.10.3-cp313-cp313t-win_amd64.whl", hash = "sha256:4f23ffe95c5667ef8a2b56eea9b53db7f43910fa4a2d5472ae0f72b64deab4d5"}, + {file = "matplotlib-3.10.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:86ab63d66bbc83fdb6733471d3bff40897c1e9921cba112accd748eee4bce5e4"}, + {file = "matplotlib-3.10.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a48f9c08bf7444b5d2391a83e75edb464ccda3c380384b36532a0962593a1751"}, + {file = "matplotlib-3.10.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb73d8aa75a237457988f9765e4dfe1c0d2453c5ca4eabc897d4309672c8e014"}, + {file = "matplotlib-3.10.3.tar.gz", hash = "sha256:2f82d2c5bb7ae93aaaa4cd42aca65d76ce6376f83304fa3a630b569aca274df0"}, ] [package.dependencies] @@ -3513,11 +3502,11 @@ files = [ [package.dependencies] numpy = [ + {version = ">=1.21"}, + {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, {version = ">=2.1.0", markers = "python_version >= \"3.13\""}, {version = ">=1.26.0", markers = "python_version == \"3.12\""}, {version = ">=1.23.3", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, - {version = ">=1.21", markers = "python_version < \"3.10\""}, ] [package.extras] @@ -3544,89 +3533,84 @@ tests = ["pytest (>=4.6)"] [[package]] name = "msgpack" -version = "1.1.0" +version = "1.1.1" description = "MessagePack serializer" optional = true python-versions = ">=3.8" groups = ["main"] files = [ - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d"}, - {file = "msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e"}, - {file = "msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68"}, - {file = "msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b"}, - {file = "msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044"}, - {file = "msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa"}, - {file = "msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59"}, - {file = "msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6"}, - {file = "msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5"}, - {file = "msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88"}, - {file = "msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2"}, - {file = "msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39"}, - {file = "msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c"}, - {file = "msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b"}, - {file = "msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b"}, - {file = "msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:071603e2f0771c45ad9bc65719291c568d4edf120b44eb36324dcb02a13bfddf"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0f92a83b84e7c0749e3f12821949d79485971f087604178026085f60ce109330"}, - {file = "msgpack-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4a1964df7b81285d00a84da4e70cb1383f2e665e0f1f2a7027e683956d04b734"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59caf6a4ed0d164055ccff8fe31eddc0ebc07cf7326a2aaa0dbf7a4001cd823e"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0907e1a7119b337971a689153665764adc34e89175f9a34793307d9def08e6ca"}, - {file = "msgpack-1.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65553c9b6da8166e819a6aa90ad15288599b340f91d18f60b2061f402b9a4915"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7a946a8992941fea80ed4beae6bff74ffd7ee129a90b4dd5cf9c476a30e9708d"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4b51405e36e075193bc051315dbf29168d6141ae2500ba8cd80a522964e31434"}, - {file = "msgpack-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4c01941fd2ff87c2a934ee6055bda4ed353a7846b8d4f341c428109e9fcde8c"}, - {file = "msgpack-1.1.0-cp313-cp313-win32.whl", hash = "sha256:7c9a35ce2c2573bada929e0b7b3576de647b0defbd25f5139dcdaba0ae35a4cc"}, - {file = "msgpack-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:bce7d9e614a04d0883af0b3d4d501171fbfca038f12c77fa838d9f198147a23f"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c40ffa9a15d74e05ba1fe2681ea33b9caffd886675412612d93ab17b58ea2fec"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1ba6136e650898082d9d5a5217d5906d1e138024f836ff48691784bbe1adf96"}, - {file = "msgpack-1.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0856a2b7e8dcb874be44fea031d22e5b3a19121be92a1e098f46068a11b0870"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:471e27a5787a2e3f974ba023f9e265a8c7cfd373632247deb225617e3100a3c7"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:646afc8102935a388ffc3914b336d22d1c2d6209c773f3eb5dd4d6d3b6f8c1cb"}, - {file = "msgpack-1.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:13599f8829cfbe0158f6456374e9eea9f44eee08076291771d8ae93eda56607f"}, - {file = "msgpack-1.1.0-cp38-cp38-win32.whl", hash = "sha256:8a84efb768fb968381e525eeeb3d92857e4985aacc39f3c47ffd00eb4509315b"}, - {file = "msgpack-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:879a7b7b0ad82481c52d3c7eb99bf6f0645dbdec5134a4bddbd16f3506947feb"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:53258eeb7a80fc46f62fd59c876957a2d0e15e6449a9e71842b6d24419d88ca1"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7e7b853bbc44fb03fbdba34feb4bd414322180135e2cb5164f20ce1c9795ee48"}, - {file = "msgpack-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3e9b4936df53b970513eac1758f3882c88658a220b58dcc1e39606dccaaf01c"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46c34e99110762a76e3911fc923222472c9d681f1094096ac4102c18319e6468"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a706d1e74dd3dea05cb54580d9bd8b2880e9264856ce5068027eed09680aa74"}, - {file = "msgpack-1.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:534480ee5690ab3cbed89d4c8971a5c631b69a8c0883ecfea96c19118510c846"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8cf9e8c3a2153934a23ac160cc4cba0ec035f6867c8013cc6077a79823370346"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3180065ec2abbe13a4ad37688b61b99d7f9e012a535b930e0e683ad6bc30155b"}, - {file = "msgpack-1.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c5a91481a3cc573ac8c0d9aace09345d989dc4a0202b7fcb312c88c26d4e71a8"}, - {file = "msgpack-1.1.0-cp39-cp39-win32.whl", hash = "sha256:f80bc7d47f76089633763f952e67f8214cb7b3ee6bfa489b3cb6a84cfac114cd"}, - {file = "msgpack-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:4d1b7ff2d6146e16e8bd665ac726a89c74163ef8cd39fa8c1087d4e52d3a2325"}, - {file = "msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e"}, + {file = "msgpack-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:353b6fc0c36fde68b661a12949d7d49f8f51ff5fa019c1e47c87c4ff34b080ed"}, + {file = "msgpack-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:79c408fcf76a958491b4e3b103d1c417044544b68e96d06432a189b43d1215c8"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78426096939c2c7482bf31ef15ca219a9e24460289c00dd0b94411040bb73ad2"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b17ba27727a36cb73aabacaa44b13090feb88a01d012c0f4be70c00f75048b4"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a17ac1ea6ec3c7687d70201cfda3b1e8061466f28f686c24f627cae4ea8efd0"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:88d1e966c9235c1d4e2afac21ca83933ba59537e2e2727a999bf3f515ca2af26"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f6d58656842e1b2ddbe07f43f56b10a60f2ba5826164910968f5933e5178af75"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96decdfc4adcbc087f5ea7ebdcfd3dee9a13358cae6e81d54be962efc38f6338"}, + {file = "msgpack-1.1.1-cp310-cp310-win32.whl", hash = "sha256:6640fd979ca9a212e4bcdf6eb74051ade2c690b862b679bfcb60ae46e6dc4bfd"}, + {file = "msgpack-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:8b65b53204fe1bd037c40c4148d00ef918eb2108d24c9aaa20bc31f9810ce0a8"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:71ef05c1726884e44f8b1d1773604ab5d4d17729d8491403a705e649116c9558"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:36043272c6aede309d29d56851f8841ba907a1a3d04435e43e8a19928e243c1d"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a32747b1b39c3ac27d0670122b57e6e57f28eefb725e0b625618d1b59bf9d1e0"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a8b10fdb84a43e50d38057b06901ec9da52baac6983d3f709d8507f3889d43f"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba0c325c3f485dc54ec298d8b024e134acf07c10d494ffa24373bea729acf704"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:88daaf7d146e48ec71212ce21109b66e06a98e5e44dca47d853cbfe171d6c8d2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8b55ea20dc59b181d3f47103f113e6f28a5e1c89fd5b67b9140edb442ab67f2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a28e8072ae9779f20427af07f53bbb8b4aa81151054e882aee333b158da8752"}, + {file = "msgpack-1.1.1-cp311-cp311-win32.whl", hash = "sha256:7da8831f9a0fdb526621ba09a281fadc58ea12701bc709e7b8cbc362feabc295"}, + {file = "msgpack-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fd1b58e1431008a57247d6e7cc4faa41c3607e8e7d4aaf81f7c29ea013cb458"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae497b11f4c21558d95de9f64fff7053544f4d1a17731c866143ed6bb4591238"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33be9ab121df9b6b461ff91baac6f2731f83d9b27ed948c5b9d1978ae28bf157"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f64ae8fe7ffba251fecb8408540c34ee9df1c26674c50c4544d72dbf792e5ce"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a494554874691720ba5891c9b0b39474ba43ffb1aaf32a5dac874effb1619e1a"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb643284ab0ed26f6957d969fe0dd8bb17beb567beb8998140b5e38a90974f6c"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d275a9e3c81b1093c060c3837e580c37f47c51eca031f7b5fb76f7b8470f5f9b"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fd6b577e4541676e0cc9ddc1709d25014d3ad9a66caa19962c4f5de30fc09ef"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb29aaa613c0a1c40d1af111abf025f1732cab333f96f285d6a93b934738a68a"}, + {file = "msgpack-1.1.1-cp312-cp312-win32.whl", hash = "sha256:870b9a626280c86cff9c576ec0d9cbcc54a1e5ebda9cd26dab12baf41fee218c"}, + {file = "msgpack-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:5692095123007180dca3e788bb4c399cc26626da51629a31d40207cb262e67f4"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3765afa6bd4832fc11c3749be4ba4b69a0e8d7b728f78e68120a157a4c5d41f0"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8ddb2bcfd1a8b9e431c8d6f4f7db0773084e107730ecf3472f1dfe9ad583f3d9"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:196a736f0526a03653d829d7d4c5500a97eea3648aebfd4b6743875f28aa2af8"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d592d06e3cc2f537ceeeb23d38799c6ad83255289bb84c2e5792e5a8dea268a"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4df2311b0ce24f06ba253fda361f938dfecd7b961576f9be3f3fbd60e87130ac"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4141c5a32b5e37905b5940aacbc59739f036930367d7acce7a64e4dec1f5e0b"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b1ce7f41670c5a69e1389420436f41385b1aa2504c3b0c30620764b15dded2e7"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4147151acabb9caed4e474c3344181e91ff7a388b888f1e19ea04f7e73dc7ad5"}, + {file = "msgpack-1.1.1-cp313-cp313-win32.whl", hash = "sha256:500e85823a27d6d9bba1d057c871b4210c1dd6fb01fbb764e37e4e8847376323"}, + {file = "msgpack-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:6d489fba546295983abd142812bda76b57e33d0b9f5d5b71c09a583285506f69"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bba1be28247e68994355e028dcd668316db30c1f758d3241a7b903ac78dcd285"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8f93dcddb243159c9e4109c9750ba5b335ab8d48d9522c5308cd05d7e3ce600"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fbbc0b906a24038c9958a1ba7ae0918ad35b06cb449d398b76a7d08470b0ed9"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:61e35a55a546a1690d9d09effaa436c25ae6130573b6ee9829c37ef0f18d5e78"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1abfc6e949b352dadf4bce0eb78023212ec5ac42f6abfd469ce91d783c149c2a"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:996f2609ddf0142daba4cefd767d6db26958aac8439ee41db9cc0db9f4c4c3a6"}, + {file = "msgpack-1.1.1-cp38-cp38-win32.whl", hash = "sha256:4d3237b224b930d58e9d83c81c0dba7aacc20fcc2f89c1e5423aa0529a4cd142"}, + {file = "msgpack-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:da8f41e602574ece93dbbda1fab24650d6bf2a24089f9e9dbb4f5730ec1e58ad"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5be6b6bc52fad84d010cb45433720327ce886009d862f46b26d4d154001994b"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a89cd8c087ea67e64844287ea52888239cbd2940884eafd2dcd25754fb72232"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d75f3807a9900a7d575d8d6674a3a47e9f227e8716256f35bc6f03fc597ffbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d182dac0221eb8faef2e6f44701812b467c02674a322c739355c39e94730cdbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b13fe0fb4aac1aa5320cd693b297fe6fdef0e7bea5518cbc2dd5299f873ae90"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:435807eeb1bc791ceb3247d13c79868deb22184e1fc4224808750f0d7d1affc1"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4835d17af722609a45e16037bb1d4d78b7bdf19d6c0128116d178956618c4e88"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8ef6e342c137888ebbfb233e02b8fbd689bb5b5fcc59b34711ac47ebd504478"}, + {file = "msgpack-1.1.1-cp39-cp39-win32.whl", hash = "sha256:61abccf9de335d9efd149e2fff97ed5974f2481b3353772e8e2dd3402ba2bd57"}, + {file = "msgpack-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:40eae974c873b2992fd36424a5d9407f93e97656d999f43fca9d29f820899084"}, + {file = "msgpack-1.1.1.tar.gz", hash = "sha256:77b79ce34a2bdab2594f490c8e80dd62a02d650b91a75159a63ec413b8d104cd"}, ] [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = true -python-versions = ">=3.5" +python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, ] [[package]] @@ -3816,6 +3800,27 @@ traitlets = ">=5.1" docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] test = ["pep440", "pre-commit", "pytest", "testpath"] +[[package]] +name = "nbsphinx" +version = "0.9.6" +description = "Jupyter Notebook Tools for Sphinx" +optional = true +python-versions = ">=3.6" +groups = ["main"] +markers = "python_version >= \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +files = [ + {file = "nbsphinx-0.9.6-py3-none-any.whl", hash = "sha256:336b0b557945a7678ec7449b16449f854bc852a435bb53b8a72e6b5dc740d992"}, + {file = "nbsphinx-0.9.6.tar.gz", hash = "sha256:c2b28a2d702f1159a95b843831798e86e60a17fc647b9bff9ba1585355de54e3"}, +] + +[package.dependencies] +docutils = ">=0.18.1" +jinja2 = "*" +nbconvert = ">=5.3,<5.4 || >5.4" +nbformat = "*" +sphinx = ">=1.8" +traitlets = ">=5" + [[package]] name = "nbsphinx" version = "0.9.7" @@ -3823,7 +3828,7 @@ description = "Jupyter Notebook Tools for Sphinx" optional = true python-versions = ">=3.6" groups = ["main"] -markers = "extra == \"dev\" or extra == \"docs\"" +markers = "python_version <= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "nbsphinx-0.9.7-py3-none-any.whl", hash = "sha256:7292c3767fea29e405c60743eee5393682a83982ab202ff98f5eb2db02629da8"}, {file = "nbsphinx-0.9.7.tar.gz", hash = "sha256:abd298a686d55fa894ef697c51d44f24e53aa312dadae38e82920f250a5456fe"}, @@ -3884,20 +3889,20 @@ files = [ [[package]] name = "notebook" -version = "7.3.3" +version = "7.4.4" description = "Jupyter Notebook - A web-based notebook environment for interactive computing" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "notebook-7.3.3-py3-none-any.whl", hash = "sha256:b193df0878956562d5171c8e25c9252b8e86c9fcc16163b8ee3fe6c5e3f422f7"}, - {file = "notebook-7.3.3.tar.gz", hash = "sha256:707a313fb882d35f921989eb3d204de942ed5132a44e4aa1fe0e8f24bb9dc25d"}, + {file = "notebook-7.4.4-py3-none-any.whl", hash = "sha256:32840f7f777b6bff79bb101159336e9b332bdbfba1495b8739e34d1d65cbc1c0"}, + {file = "notebook-7.4.4.tar.gz", hash = "sha256:392fd501e266f2fb3466c6fcd3331163a2184968cb5c5accf90292e01dfe528c"}, ] [package.dependencies] jupyter-server = ">=2.4.0,<3" -jupyterlab = ">=4.3.6,<4.4" +jupyterlab = ">=4.4.4,<4.5" jupyterlab-server = ">=2.27.1,<3" notebook-shim = ">=0.2,<0.3" tornado = ">=6.2.0" @@ -3984,137 +3989,204 @@ files = [ [[package]] name = "numpy" -version = "2.2.4" +version = "2.2.6" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version >= \"3.10\"" -files = [ - {file = "numpy-2.2.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8146f3550d627252269ac42ae660281d673eb6f8b32f113538e0cc2a9aed42b9"}, - {file = "numpy-2.2.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e642d86b8f956098b564a45e6f6ce68a22c2c97a04f5acd3f221f57b8cb850ae"}, - {file = "numpy-2.2.4-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:a84eda42bd12edc36eb5b53bbcc9b406820d3353f1994b6cfe453a33ff101775"}, - {file = "numpy-2.2.4-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:4ba5054787e89c59c593a4169830ab362ac2bee8a969249dc56e5d7d20ff8df9"}, - {file = "numpy-2.2.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7716e4a9b7af82c06a2543c53ca476fa0b57e4d760481273e09da04b74ee6ee2"}, - {file = "numpy-2.2.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:adf8c1d66f432ce577d0197dceaac2ac00c0759f573f28516246351c58a85020"}, - {file = "numpy-2.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:218f061d2faa73621fa23d6359442b0fc658d5b9a70801373625d958259eaca3"}, - {file = "numpy-2.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:df2f57871a96bbc1b69733cd4c51dc33bea66146b8c63cacbfed73eec0883017"}, - {file = "numpy-2.2.4-cp310-cp310-win32.whl", hash = "sha256:a0258ad1f44f138b791327961caedffbf9612bfa504ab9597157806faa95194a"}, - {file = "numpy-2.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:0d54974f9cf14acf49c60f0f7f4084b6579d24d439453d5fc5805d46a165b542"}, - {file = "numpy-2.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4"}, - {file = "numpy-2.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4"}, - {file = "numpy-2.2.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f"}, - {file = "numpy-2.2.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880"}, - {file = "numpy-2.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1"}, - {file = "numpy-2.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5"}, - {file = "numpy-2.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687"}, - {file = "numpy-2.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6"}, - {file = "numpy-2.2.4-cp311-cp311-win32.whl", hash = "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09"}, - {file = "numpy-2.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91"}, - {file = "numpy-2.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4"}, - {file = "numpy-2.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854"}, - {file = "numpy-2.2.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24"}, - {file = "numpy-2.2.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee"}, - {file = "numpy-2.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba"}, - {file = "numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592"}, - {file = "numpy-2.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb"}, - {file = "numpy-2.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f"}, - {file = "numpy-2.2.4-cp312-cp312-win32.whl", hash = "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00"}, - {file = "numpy-2.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146"}, - {file = "numpy-2.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7"}, - {file = "numpy-2.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0"}, - {file = "numpy-2.2.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392"}, - {file = "numpy-2.2.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc"}, - {file = "numpy-2.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298"}, - {file = "numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7"}, - {file = "numpy-2.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6"}, - {file = "numpy-2.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd"}, - {file = "numpy-2.2.4-cp313-cp313-win32.whl", hash = "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c"}, - {file = "numpy-2.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3"}, - {file = "numpy-2.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8"}, - {file = "numpy-2.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39"}, - {file = "numpy-2.2.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd"}, - {file = "numpy-2.2.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0"}, - {file = "numpy-2.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960"}, - {file = "numpy-2.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8"}, - {file = "numpy-2.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc"}, - {file = "numpy-2.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff"}, - {file = "numpy-2.2.4-cp313-cp313t-win32.whl", hash = "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286"}, - {file = "numpy-2.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d"}, - {file = "numpy-2.2.4-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7051ee569db5fbac144335e0f3b9c2337e0c8d5c9fee015f259a5bd70772b7e8"}, - {file = "numpy-2.2.4-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ab2939cd5bec30a7430cbdb2287b63151b77cf9624de0532d629c9a1c59b1d5c"}, - {file = "numpy-2.2.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f35b19894a9e08639fd60a1ec1978cb7f5f7f1eace62f38dd36be8aecdef4d"}, - {file = "numpy-2.2.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b4adfbbc64014976d2f91084915ca4e626fbf2057fb81af209c1a6d776d23e3d"}, - {file = "numpy-2.2.4.tar.gz", hash = "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f"}, +markers = "python_version == \"3.10\"" +files = [ + {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"}, + {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"}, + {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"}, + {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"}, + {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"}, + {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42"}, + {file = "numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a"}, + {file = "numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1"}, + {file = "numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab"}, + {file = "numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47"}, + {file = "numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3"}, + {file = "numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87"}, + {file = "numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49"}, + {file = "numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de"}, + {file = "numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4"}, + {file = "numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d"}, + {file = "numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f"}, + {file = "numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868"}, + {file = "numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d"}, + {file = "numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd"}, + {file = "numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40"}, + {file = "numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f"}, + {file = "numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571"}, + {file = "numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1"}, + {file = "numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff"}, + {file = "numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"}, + {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"}, + {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"}, +] + +[[package]] +name = "numpy" +version = "2.3.1" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "numpy-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ea9e48336a402551f52cd8f593343699003d2353daa4b72ce8d34f66b722070"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccb7336eaf0e77c1635b232c141846493a588ec9ea777a7c24d7166bb8533ae"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0bb3a4a61e1d327e035275d2a993c96fa786e4913aa089843e6a2d9dd205c66a"}, + {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:e344eb79dab01f1e838ebb67aab09965fb271d6da6b00adda26328ac27d4a66e"}, + {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:467db865b392168ceb1ef1ffa6f5a86e62468c43e0cfb4ab6da667ede10e58db"}, + {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:afed2ce4a84f6b0fc6c1ce734ff368cbf5a5e24e8954a338f3bdffa0718adffb"}, + {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0025048b3c1557a20bc80d06fdeb8cc7fc193721484cca82b2cfa072fec71a93"}, + {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5ee121b60aa509679b682819c602579e1df14a5b07fe95671c8849aad8f2115"}, + {file = "numpy-2.3.1-cp311-cp311-win32.whl", hash = "sha256:a8b740f5579ae4585831b3cf0e3b0425c667274f82a484866d2adf9570539369"}, + {file = "numpy-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4580adadc53311b163444f877e0789f1c8861e2698f6b2a4ca852fda154f3ff"}, + {file = "numpy-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:ec0bdafa906f95adc9a0c6f26a4871fa753f25caaa0e032578a30457bff0af6a"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc"}, + {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943"}, + {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25"}, + {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660"}, + {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952"}, + {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77"}, + {file = "numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab"}, + {file = "numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76"}, + {file = "numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0"}, + {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d"}, + {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1"}, + {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1"}, + {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0"}, + {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8"}, + {file = "numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8"}, + {file = "numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42"}, + {file = "numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee"}, + {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992"}, + {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c"}, + {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48"}, + {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee"}, + {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280"}, + {file = "numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e"}, + {file = "numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc"}, + {file = "numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ad506d4b09e684394c42c966ec1527f6ebc25da7f4da4b1b056606ffe446b8a3"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ebb8603d45bc86bbd5edb0d63e52c5fd9e7945d3a503b77e486bd88dde67a19b"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:15aa4c392ac396e2ad3d0a2680c0f0dee420f9fed14eef09bdb9450ee6dcb7b7"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c6e0bf9d1a2f50d2b65a7cf56db37c095af17b59f6c132396f7c6d5dd76484df"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eabd7e8740d494ce2b4ea0ff05afa1b7b291e978c0ae075487c51e8bd93c0c68"}, + {file = "numpy-2.3.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e610832418a2bc09d974cc9fecebfa51e9532d6190223bc5ef6a7402ebf3b5cb"}, + {file = "numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b"}, ] [[package]] name = "nvidia-cublas-cu12" -version = "12.4.5.8" +version = "12.6.4.1" description = "CUBLAS native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0f8aa1706812e00b9f19dfe0cdb3999b092ccb8ca168c0db5b8ea712456fd9b3"}, - {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2fc8da60df463fdefa81e323eef2e36489e1c94335b5358bcb38360adf75ac9b"}, - {file = "nvidia_cublas_cu12-12.4.5.8-py3-none-win_amd64.whl", hash = "sha256:5a796786da89203a0657eda402bcdcec6180254a8ac22d72213abc42069522dc"}, + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08ed2686e9875d01b58e3cb379c6896df8e76c75e0d4a7f7dace3d7b6d9ef8eb"}, + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:235f728d6e2a409eddf1df58d5b0921cf80cfa9e72b9f2775ccb7b4a87984668"}, + {file = "nvidia_cublas_cu12-12.6.4.1-py3-none-win_amd64.whl", hash = "sha256:9e4fa264f4d8a4eb0cdbd34beadc029f453b3bafae02401e999cf3d5a5af75f8"}, ] [[package]] name = "nvidia-cuda-cupti-cu12" -version = "12.4.127" +version = "12.6.80" description = "CUDA profiling tools runtime libs." optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:79279b35cf6f91da114182a5ce1864997fd52294a87a16179ce275773799458a"}, - {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:9dec60f5ac126f7bb551c055072b69d85392b13311fcc1bcda2202d172df30fb"}, - {file = "nvidia_cuda_cupti_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:5688d203301ab051449a2b1cb6690fbe90d2b372f411521c86018b950f3d7922"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:166ee35a3ff1587f2490364f90eeeb8da06cd867bd5b701bf7f9a02b78bc63fc"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_aarch64.whl", hash = "sha256:358b4a1d35370353d52e12f0a7d1769fc01ff74a191689d3870b2123156184c4"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6768bad6cab4f19e8292125e5f1ac8aa7d1718704012a0e3272a6f61c4bce132"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a3eff6cdfcc6a4c35db968a06fcadb061cbc7d6dde548609a941ff8701b98b73"}, + {file = "nvidia_cuda_cupti_cu12-12.6.80-py3-none-win_amd64.whl", hash = "sha256:bbe6ae76e83ce5251b56e8c8e61a964f757175682bbad058b170b136266ab00a"}, ] [[package]] name = "nvidia-cuda-nvrtc-cu12" -version = "12.4.127" +version = "12.6.77" description = "NVRTC native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0eedf14185e04b76aa05b1fea04133e59f465b6f960c0cbf4e37c3cb6b0ea198"}, - {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a178759ebb095827bd30ef56598ec182b85547f1508941a3d560eb7ea1fbf338"}, - {file = "nvidia_cuda_nvrtc_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:a961b2f1d5f17b14867c619ceb99ef6fcec12e46612711bcec78eb05068a60ec"}, + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5847f1d6e5b757f1d2b3991a01082a44aad6f10ab3c5c0213fa3e25bddc25a13"}, + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:35b0cc6ee3a9636d5409133e79273ce1f3fd087abb0532d2d2e8fff1fe9efc53"}, + {file = "nvidia_cuda_nvrtc_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:f7007dbd914c56bd80ea31bc43e8e149da38f68158f423ba845fc3292684e45a"}, ] [[package]] name = "nvidia-cuda-runtime-cu12" -version = "12.4.127" +version = "12.6.77" description = "CUDA Runtime native Libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:961fe0e2e716a2a1d967aab7caee97512f71767f852f67432d572e36cb3a11f3"}, - {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:64403288fa2136ee8e467cdc9c9427e0434110899d07c779f25b5c068934faa5"}, - {file = "nvidia_cuda_runtime_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:09c2e35f48359752dfa822c09918211844a3d93c100a715d79b59591130c5e1e"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6116fad3e049e04791c0256a9778c16237837c08b27ed8c8401e2e45de8d60cd"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d461264ecb429c84c8879a7153499ddc7b19b5f8d84c204307491989a365588e"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba3b56a4f896141e25e19ab287cd71e52a6a0f4b29d0d31609f60e3b4d5219b7"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a84d15d5e1da416dd4774cb42edf5e954a3e60cc945698dc1d5be02321c44dc8"}, + {file = "nvidia_cuda_runtime_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:86c58044c824bf3c173c49a2dbc7a6c8b53cb4e4dca50068be0bf64e9dab3f7f"}, ] [[package]] name = "nvidia-cudnn-cu12" -version = "9.1.0.70" +version = "9.5.1.17" description = "cuDNN runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f"}, - {file = "nvidia_cudnn_cu12-9.1.0.70-py3-none-win_amd64.whl", hash = "sha256:6278562929433d68365a07a4a1546c237ba2849852c0d4b2262a486e805b977a"}, + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9fd4584468533c61873e5fda8ca41bac3a38bcb2d12350830c69b0a96a7e4def"}, + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:30ac3869f6db17d170e0e556dd6cc5eee02647abc31ca856634d5a40f82c15b2"}, + {file = "nvidia_cudnn_cu12-9.5.1.17-py3-none-win_amd64.whl", hash = "sha256:d7af0f8a4f3b4b9dbb3122f2ef553b45694ed9c384d5a75bab197b8eefb79ab8"}, ] [package.dependencies] @@ -4122,47 +4194,66 @@ nvidia-cublas-cu12 = "*" [[package]] name = "nvidia-cufft-cu12" -version = "11.2.1.3" +version = "11.3.0.4" description = "CUFFT native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399"}, - {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f083fc24912aa410be21fa16d157fed2055dab1cc4b6934a0e03cba69eb242b9"}, - {file = "nvidia_cufft_cu12-11.2.1.3-py3-none-win_amd64.whl", hash = "sha256:d802f4954291101186078ccbe22fc285a902136f974d369540fd4a5333d1440b"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d16079550df460376455cba121db6564089176d9bac9e4f360493ca4741b22a6"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8510990de9f96c803a051822618d42bf6cb8f069ff3f48d93a8486efdacb48fb"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ccba62eb9cef5559abd5e0d54ceed2d9934030f51163df018532142a8ec533e5"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-manylinux2014_x86_64.whl", hash = "sha256:768160ac89f6f7b459bee747e8d175dbf53619cfe74b2a5636264163138013ca"}, + {file = "nvidia_cufft_cu12-11.3.0.4-py3-none-win_amd64.whl", hash = "sha256:6048ebddfb90d09d2707efb1fd78d4e3a77cb3ae4dc60e19aab6be0ece2ae464"}, ] [package.dependencies] nvidia-nvjitlink-cu12 = "*" +[[package]] +name = "nvidia-cufile-cu12" +version = "1.11.1.6" +description = "cuFile GPUDirect libraries" +optional = true +python-versions = ">=3" +groups = ["main"] +markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" +files = [ + {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc23469d1c7e52ce6c1d55253273d32c565dd22068647f3aa59b3c6b005bf159"}, + {file = "nvidia_cufile_cu12-1.11.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:8f57a0051dcf2543f6dc2b98a98cb2719c37d3cee1baba8965d57f3bbc90d4db"}, +] + [[package]] name = "nvidia-curand-cu12" -version = "10.3.5.147" +version = "10.3.7.77" description = "CURAND native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1f173f09e3e3c76ab084aba0de819c49e56614feae5c12f69883f4ae9bb5fad9"}, - {file = "nvidia_curand_cu12-10.3.5.147-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a88f583d4e0bb643c49743469964103aa59f7f708d862c3ddb0fc07f851e3b8b"}, - {file = "nvidia_curand_cu12-10.3.5.147-py3-none-win_amd64.whl", hash = "sha256:f307cc191f96efe9e8f05a87096abc20d08845a841889ef78cb06924437f6771"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:6e82df077060ea28e37f48a3ec442a8f47690c7499bff392a5938614b56c98d8"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a42cd1344297f70b9e39a1e4f467a4e1c10f1da54ff7a85c12197f6c652c8bdf"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:99f1a32f1ac2bd134897fc7a203f779303261268a65762a623bf30cc9fe79117"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:7b2ed8e95595c3591d984ea3603dd66fe6ce6812b886d59049988a712ed06b6e"}, + {file = "nvidia_curand_cu12-10.3.7.77-py3-none-win_amd64.whl", hash = "sha256:6d6d935ffba0f3d439b7cd968192ff068fafd9018dbf1b85b37261b13cfc9905"}, ] [[package]] name = "nvidia-cusolver-cu12" -version = "11.6.1.9" +version = "11.7.1.2" description = "CUDA solver native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e"}, - {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_x86_64.whl", hash = "sha256:19e33fa442bcfd085b3086c4ebf7e8debc07cfe01e11513cc6d332fd918ac260"}, - {file = "nvidia_cusolver_cu12-11.6.1.9-py3-none-win_amd64.whl", hash = "sha256:e77314c9d7b694fcebc84f58989f3aa4fb4cb442f12ca1a9bde50f5e8f6d1b9c"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0ce237ef60acde1efc457335a2ddadfd7610b892d94efee7b776c64bb1cac9e0"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e9e49843a7707e42022babb9bcfa33c29857a93b88020c4e4434656a655b698c"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf28f17f64107a0c4d7802be5ff5537b2130bfc112f25d5a30df227058ca0e6"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dbbe4fc38ec1289c7e5230e16248365e375c3673c9c8bac5796e2e20db07f56e"}, + {file = "nvidia_cusolver_cu12-11.7.1.2-py3-none-win_amd64.whl", hash = "sha256:6813f9d8073f555444a8705f3ab0296d3e1cb37a16d694c5fc8b862a0d8706d7"}, ] [package.dependencies] @@ -4172,16 +4263,18 @@ nvidia-nvjitlink-cu12 = "*" [[package]] name = "nvidia-cusparse-cu12" -version = "12.3.1.170" +version = "12.5.4.2" description = "CUSPARSE native runtime libraries" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3"}, - {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ea4f11a2904e2a8dc4b1833cc1b5181cde564edd0d5cd33e3c168eff2d1863f1"}, - {file = "nvidia_cusparse_cu12-12.3.1.170-py3-none-win_amd64.whl", hash = "sha256:9bc90fb087bc7b4c15641521f31c0371e9a612fc2ba12c338d3ae032e6b6797f"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d25b62fb18751758fe3c93a4a08eff08effedfe4edf1c6bb5afd0890fe88f887"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7aa32fa5470cf754f72d1116c7cbc300b4e638d3ae5304cfa4a638a5b87161b1"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7556d9eca156e18184b94947ade0fba5bb47d69cec46bf8660fd2c71a4b48b73"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:23749a6571191a215cb74d1cdbff4a86e7b19f1200c071b3fcf844a5bea23a2f"}, + {file = "nvidia_cusparse_cu12-12.5.4.2-py3-none-win_amd64.whl", hash = "sha256:4acb8c08855a26d737398cba8fb6f8f5045d93f82612b4cfd84645a2332ccf20"}, ] [package.dependencies] @@ -4189,56 +4282,59 @@ nvidia-nvjitlink-cu12 = "*" [[package]] name = "nvidia-cusparselt-cu12" -version = "0.6.2" +version = "0.6.3" description = "NVIDIA cuSPARSELt" optional = true python-versions = "*" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:067a7f6d03ea0d4841c85f0c6f1991c5dda98211f6302cb83a4ab234ee95bef8"}, - {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:df2c24502fd76ebafe7457dbc4716b2fec071aabaed4fb7691a201cde03704d9"}, - {file = "nvidia_cusparselt_cu12-0.6.2-py3-none-win_amd64.whl", hash = "sha256:0057c91d230703924c0422feabe4ce768841f9b4b44d28586b6f6d2eb86fbe70"}, + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8371549623ba601a06322af2133c4a44350575f5a3108fb75f3ef20b822ad5f1"}, + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e5c8a26c36445dd2e6812f1177978a24e2d37cacce7e090f297a688d1ec44f46"}, + {file = "nvidia_cusparselt_cu12-0.6.3-py3-none-win_amd64.whl", hash = "sha256:3b325bcbd9b754ba43df5a311488fca11a6b5dc3d11df4d190c000cf1a0765c7"}, ] [[package]] name = "nvidia-nccl-cu12" -version = "2.21.5" +version = "2.26.2" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_nccl_cu12-2.21.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8579076d30a8c24988834445f8d633c697d42397e92ffc3f63fa26766d25e0a0"}, + {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c196e95e832ad30fbbb50381eb3cbd1fadd5675e587a548563993609af19522"}, + {file = "nvidia_nccl_cu12-2.26.2-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:694cf3879a206553cc9d7dbda76b13efaf610fdb70a50cba303de1b0d1530ac6"}, ] [[package]] name = "nvidia-nvjitlink-cu12" -version = "12.4.127" +version = "12.6.85" description = "Nvidia JIT LTO Library" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:4abe7fef64914ccfa909bc2ba39739670ecc9e820c83ccc7a6ed414122599b83"}, - {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"}, - {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:eedc36df9e88b682efe4309aa16b5b4e78c2407eac59e8c10a6a47535164369a"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cf4eaa7d4b6b543ffd69d6abfb11efdeb2db48270d94dfd3a452c24150829e41"}, + {file = "nvidia_nvjitlink_cu12-12.6.85-py3-none-win_amd64.whl", hash = "sha256:e61120e52ed675747825cdd16febc6a0730537451d867ee58bee3853b1b13d1c"}, ] [[package]] name = "nvidia-nvtx-cu12" -version = "12.4.127" +version = "12.6.77" description = "NVIDIA Tools Extension" optional = true python-versions = ">=3" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7959ad635db13edf4fc65c06a6e9f9e55fc2f92596db928d169c0bb031e88ef3"}, - {file = "nvidia_nvtx_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:781e950d9b9f60d8241ccea575b32f5105a5baf4c2351cab5256a24869f12a1a"}, - {file = "nvidia_nvtx_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:641dccaaa1139f3ffb0d3164b4b84f9d253397e38246a4f2f36728b48566d485"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f44f8d86bb7d5629988d61c8d3ae61dddb2015dee142740536bc7481b022fe4b"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_aarch64.whl", hash = "sha256:adcaabb9d436c9761fca2b13959a2d237c5f9fd406c8e4b723c695409ff88059"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b90bed3df379fa79afbd21be8e04a0314336b8ae16768b58f2d34cb1d04cd7d2"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6574241a3ec5fdc9334353ab8c479fe75841dbe8f4532a8fc97ce63503330ba1"}, + {file = "nvidia_nvtx_cu12-12.6.77-py3-none-win_amd64.whl", hash = "sha256:2fb11a4af04a5e6c84073e6404d26588a34afd35379f0855a99797897efa75c0"}, ] [[package]] @@ -4260,6 +4356,7 @@ description = "A gradient processing and optimization library in JAX." optional = true python-versions = ">=3.9" groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "optax-0.2.4-py3-none-any.whl", hash = "sha256:db35c04e50b52596662efb002334de08c2a0a74971e4da33f467e84fac08886a"}, {file = "optax-0.2.4.tar.gz", hash = "sha256:4e05d3d5307e6dde4c319187ae36e6cd3a0c035d4ed25e9e992449a304f47336"}, @@ -4279,6 +4376,30 @@ dp-accounting = ["absl-py (>=1.0.0)", "attrs (>=21.4.0)", "mpmath (>=1.2.1)", "n examples = ["dp_accounting (>=0.4)", "flax", "ipywidgets", "tensorflow (>=2.4.0)", "tensorflow-datasets (>=4.2.0)"] test = ["dm-tree (>=0.1.7)", "flax (>=0.5.3)", "scikit-learn", "scipy (>=1.7.1)"] +[[package]] +name = "optax" +version = "0.2.5" +description = "A gradient processing and optimization library in JAX." +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "optax-0.2.5-py3-none-any.whl", hash = "sha256:966deae936207f268ac8f564d8ed228d645ac1aaddefbbf194096d2299b24ba8"}, + {file = "optax-0.2.5.tar.gz", hash = "sha256:b2e38c7aea376186deae758ba7a258e6ef760c6f6131e9e11bc561c65386d594"}, +] + +[package.dependencies] +absl-py = ">=0.7.1" +chex = ">=0.1.87" +jax = ">=0.4.27" +jaxlib = ">=0.4.27" +numpy = ">=1.18.0" + +[package.extras] +docs = ["flax", "ipython (>=8.8.0)", "matplotlib (>=3.5.0)", "myst-nb (>=1.0.0)", "sphinx (>=6.0.0)", "sphinx-autodoc-typehints", "sphinx-book-theme (>=1.0.1)", "sphinx-collections (>=0.0.1)", "sphinx-gallery (>=0.14.0)", "sphinx_contributors", "sphinxcontrib-katex"] +test = ["flax (>=0.5.3)", "scikit-learn", "scipy (>=1.7.1)"] + [[package]] name = "orbax-checkpoint" version = "0.6.4" @@ -4311,15 +4432,15 @@ testing = ["flax", "google-cloud-logging", "mock", "pytest", "pytest-xdist"] [[package]] name = "orbax-checkpoint" -version = "0.11.10" +version = "0.11.18" description = "Orbax Checkpoint" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "orbax_checkpoint-0.11.10-py3-none-any.whl", hash = "sha256:11e20aa97a3b0ddef79a24cf192fd997298604ab5541dc4f3ec7512ecbe94bdf"}, - {file = "orbax_checkpoint-0.11.10.tar.gz", hash = "sha256:9e415b0d041b4c256ff2e126df9c6b056f0155f322de0a69befd73d1657fb9e5"}, + {file = "orbax_checkpoint-0.11.18-py3-none-any.whl", hash = "sha256:9f2f1ebc0305d75593e5720aeb8a82ee42c68f436ef98840411b2804136f7034"}, + {file = "orbax_checkpoint-0.11.18.tar.gz", hash = "sha256:de7c3826550fc5fed1eb362be30e4b83125cb32bb86de951652bb3c4f9337415"}, ] [package.dependencies] @@ -4337,97 +4458,90 @@ tensorstore = ">=0.1.71" typing_extensions = "*" [package.extras] -docs = ["flax", "google-cloud-logging"] -testing = ["chex", "flax", "google-cloud-logging", "mock", "pytest", "pytest-xdist"] +docs = ["flax", "google-cloud-logging", "grain", "opencv-python", "tensorflow_datasets"] +testing = ["aiofiles", "chex", "flax", "google-cloud-logging", "mock", "pytest", "pytest-xdist"] [[package]] name = "orjson" -version = "3.10.15" +version = "3.10.18" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf"}, - {file = "orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182"}, - {file = "orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e"}, - {file = "orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab"}, - {file = "orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806"}, - {file = "orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13"}, - {file = "orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388"}, - {file = "orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c"}, - {file = "orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e"}, - {file = "orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e"}, - {file = "orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41"}, - {file = "orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7"}, - {file = "orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a"}, - {file = "orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665"}, - {file = "orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa"}, - {file = "orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e"}, - {file = "orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561"}, - {file = "orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825"}, - {file = "orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890"}, - {file = "orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf"}, - {file = "orjson-3.10.15-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e8afd6200e12771467a1a44e5ad780614b86abb4b11862ec54861a82d677746"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9a18c500f19273e9e104cca8c1f0b40a6470bcccfc33afcc088045d0bf5ea6"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb00b7bfbdf5d34a13180e4805d76b4567025da19a197645ca746fc2fb536586"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33aedc3d903378e257047fee506f11e0833146ca3e57a1a1fb0ddb789876c1e1"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd0099ae6aed5eb1fc84c9eb72b95505a3df4267e6962eb93cdd5af03be71c98"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c864a80a2d467d7786274fce0e4f93ef2a7ca4ff31f7fc5634225aaa4e9e98c"}, - {file = "orjson-3.10.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c25774c9e88a3e0013d7d1a6c8056926b607a61edd423b50eb5c88fd7f2823ae"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:e78c211d0074e783d824ce7bb85bf459f93a233eb67a5b5003498232ddfb0e8a"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:43e17289ffdbbac8f39243916c893d2ae41a2ea1a9cbb060a56a4d75286351ae"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:781d54657063f361e89714293c095f506c533582ee40a426cb6489c48a637b81"}, - {file = "orjson-3.10.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6875210307d36c94873f553786a808af2788e362bd0cf4c8e66d976791e7b528"}, - {file = "orjson-3.10.15-cp38-cp38-win32.whl", hash = "sha256:305b38b2b8f8083cc3d618927d7f424349afce5975b316d33075ef0f73576b60"}, - {file = "orjson-3.10.15-cp38-cp38-win_amd64.whl", hash = "sha256:5dd9ef1639878cc3efffed349543cbf9372bdbd79f478615a1c633fe4e4180d1"}, - {file = "orjson-3.10.15-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ffe19f3e8d68111e8644d4f4e267a069ca427926855582ff01fc012496d19969"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d433bf32a363823863a96561a555227c18a522a8217a6f9400f00ddc70139ae2"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:da03392674f59a95d03fa5fb9fe3a160b0511ad84b7a3914699ea5a1b3a38da2"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a63bb41559b05360ded9132032239e47983a39b151af1201f07ec9370715c82"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3766ac4702f8f795ff3fa067968e806b4344af257011858cc3d6d8721588b53f"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a1c73dcc8fadbd7c55802d9aa093b36878d34a3b3222c41052ce6b0fc65f8e8"}, - {file = "orjson-3.10.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b299383825eafe642cbab34be762ccff9fd3408d72726a6b2a4506d410a71ab3"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:abc7abecdbf67a173ef1316036ebbf54ce400ef2300b4e26a7b843bd446c2480"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3614ea508d522a621384c1d6639016a5a2e4f027f3e4a1c93a51867615d28829"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:295c70f9dc154307777ba30fe29ff15c1bcc9dfc5c48632f37d20a607e9ba85a"}, - {file = "orjson-3.10.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:63309e3ff924c62404923c80b9e2048c1f74ba4b615e7584584389ada50ed428"}, - {file = "orjson-3.10.15-cp39-cp39-win32.whl", hash = "sha256:a2f708c62d026fb5340788ba94a55c23df4e1869fec74be455e0b2f5363b8507"}, - {file = "orjson-3.10.15-cp39-cp39-win_amd64.whl", hash = "sha256:efcf6c735c3d22ef60c4aa27a5238f1a477df85e9b15f2142f9d669beb2d13fd"}, - {file = "orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e"}, + {file = "orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f"}, + {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8"}, + {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f"}, + {file = "orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06"}, + {file = "orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92"}, + {file = "orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8"}, + {file = "orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4"}, + {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b"}, + {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7"}, + {file = "orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1"}, + {file = "orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a"}, + {file = "orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5"}, + {file = "orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753"}, + {file = "orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad"}, + {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06"}, + {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5"}, + {file = "orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e"}, + {file = "orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc"}, + {file = "orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a"}, + {file = "orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147"}, + {file = "orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049"}, + {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012"}, + {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f"}, + {file = "orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea"}, + {file = "orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"}, + {file = "orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3"}, + {file = "orjson-3.10.18-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95fae14225edfd699454e84f61c3dd938df6629a00c6ce15e704f57b58433bb"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5232d85f177f98e0cefabb48b5e7f60cff6f3f0365f9c60631fecd73849b2a82"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2783e121cafedf0d85c148c248a20470018b4ffd34494a68e125e7d5857655d1"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e54ee3722caf3db09c91f442441e78f916046aa58d16b93af8a91500b7bbf273"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2daf7e5379b61380808c24f6fc182b7719301739e4271c3ec88f2984a2d61f89"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f39b371af3add20b25338f4b29a8d6e79a8c7ed0e9dd49e008228a065d07781"}, + {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b819ed34c01d88c6bec290e6842966f8e9ff84b7694632e88341363440d4cc0"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2f6c57debaef0b1aa13092822cbd3698a1fb0209a9ea013a969f4efa36bdea57"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:755b6d61ffdb1ffa1e768330190132e21343757c9aa2308c67257cc81a1a6f5a"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce8d0a875a85b4c8579eab5ac535fb4b2a50937267482be402627ca7e7570ee3"}, + {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57b5d0673cbd26781bebc2bf86f99dd19bd5a9cb55f71cc4f66419f6b50f3d77"}, + {file = "orjson-3.10.18-cp39-cp39-win32.whl", hash = "sha256:951775d8b49d1d16ca8818b1f20c4965cae9157e7b562a2ae34d3967b8f21c8e"}, + {file = "orjson-3.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:fdd9d68f83f0bc4406610b1ac68bdcded8c5ee58605cc69e643a06f4d075f429"}, + {file = "orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53"}, ] [[package]] @@ -4445,73 +4559,73 @@ files = [ [[package]] name = "packaging" -version = "24.2" +version = "25.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, - {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] name = "pandas" -version = "2.2.3" +version = "2.3.1" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"}, - {file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"}, - {file = "pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed"}, - {file = "pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57"}, - {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42"}, - {file = "pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f"}, - {file = "pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645"}, - {file = "pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039"}, - {file = "pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd"}, - {file = "pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698"}, - {file = "pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc"}, - {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3"}, - {file = "pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32"}, - {file = "pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5"}, - {file = "pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9"}, - {file = "pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4"}, - {file = "pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3"}, - {file = "pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319"}, - {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8"}, - {file = "pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a"}, - {file = "pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13"}, - {file = "pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015"}, - {file = "pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28"}, - {file = "pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0"}, - {file = "pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24"}, - {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659"}, - {file = "pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb"}, - {file = "pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d"}, - {file = "pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468"}, - {file = "pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18"}, - {file = "pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2"}, - {file = "pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4"}, - {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d"}, - {file = "pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a"}, - {file = "pandas-2.2.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc6b93f9b966093cb0fd62ff1a7e4c09e6d546ad7c1de191767baffc57628f39"}, - {file = "pandas-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5dbca4c1acd72e8eeef4753eeca07de9b1db4f398669d5994086f788a5d7cc30"}, - {file = "pandas-2.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8cd6d7cc958a3910f934ea8dbdf17b2364827bb4dafc38ce6eef6bb3d65ff09c"}, - {file = "pandas-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99df71520d25fade9db7c1076ac94eb994f4d2673ef2aa2e86ee039b6746d20c"}, - {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:31d0ced62d4ea3e231a9f228366919a5ea0b07440d9d4dac345376fd8e1477ea"}, - {file = "pandas-2.2.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7eee9e7cea6adf3e3d24e304ac6b8300646e2a5d1cd3a3c2abed9101b0846761"}, - {file = "pandas-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4850ba03528b6dd51d6c5d273c46f183f39a9baf3f0143e566b89450965b105e"}, - {file = "pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667"}, + {file = "pandas-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:22c2e866f7209ebc3a8f08d75766566aae02bcc91d196935a1d9e59c7b990ac9"}, + {file = "pandas-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3583d348546201aff730c8c47e49bc159833f971c2899d6097bce68b9112a4f1"}, + {file = "pandas-2.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f951fbb702dacd390561e0ea45cdd8ecfa7fb56935eb3dd78e306c19104b9b0"}, + {file = "pandas-2.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd05b72ec02ebfb993569b4931b2e16fbb4d6ad6ce80224a3ee838387d83a191"}, + {file = "pandas-2.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1b916a627919a247d865aed068eb65eb91a344b13f5b57ab9f610b7716c92de1"}, + {file = "pandas-2.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fe67dc676818c186d5a3d5425250e40f179c2a89145df477dd82945eaea89e97"}, + {file = "pandas-2.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:2eb789ae0274672acbd3c575b0598d213345660120a257b47b5dafdc618aec83"}, + {file = "pandas-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2b0540963d83431f5ce8870ea02a7430adca100cec8a050f0811f8e31035541b"}, + {file = "pandas-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fe7317f578c6a153912bd2292f02e40c1d8f253e93c599e82620c7f69755c74f"}, + {file = "pandas-2.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6723a27ad7b244c0c79d8e7007092d7c8f0f11305770e2f4cd778b3ad5f9f85"}, + {file = "pandas-2.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3462c3735fe19f2638f2c3a40bd94ec2dc5ba13abbb032dd2fa1f540a075509d"}, + {file = "pandas-2.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:98bcc8b5bf7afed22cc753a28bc4d9e26e078e777066bc53fac7904ddef9a678"}, + {file = "pandas-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4d544806b485ddf29e52d75b1f559142514e60ef58a832f74fb38e48d757b299"}, + {file = "pandas-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:b3cd4273d3cb3707b6fffd217204c52ed92859533e31dc03b7c5008aa933aaab"}, + {file = "pandas-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:689968e841136f9e542020698ee1c4fbe9caa2ed2213ae2388dc7b81721510d3"}, + {file = "pandas-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:025e92411c16cbe5bb2a4abc99732a6b132f439b8aab23a59fa593eb00704232"}, + {file = "pandas-2.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b7ff55f31c4fcb3e316e8f7fa194566b286d6ac430afec0d461163312c5841e"}, + {file = "pandas-2.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7dcb79bf373a47d2a40cf7232928eb7540155abbc460925c2c96d2d30b006eb4"}, + {file = "pandas-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56a342b231e8862c96bdb6ab97170e203ce511f4d0429589c8ede1ee8ece48b8"}, + {file = "pandas-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ca7ed14832bce68baef331f4d7f294411bed8efd032f8109d690df45e00c4679"}, + {file = "pandas-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:ac942bfd0aca577bef61f2bc8da8147c4ef6879965ef883d8e8d5d2dc3e744b8"}, + {file = "pandas-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9026bd4a80108fac2239294a15ef9003c4ee191a0f64b90f170b40cfb7cf2d22"}, + {file = "pandas-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6de8547d4fdb12421e2d047a2c446c623ff4c11f47fddb6b9169eb98ffba485a"}, + {file = "pandas-2.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:782647ddc63c83133b2506912cc6b108140a38a37292102aaa19c81c83db2928"}, + {file = "pandas-2.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ba6aff74075311fc88504b1db890187a3cd0f887a5b10f5525f8e2ef55bfdb9"}, + {file = "pandas-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e5635178b387bd2ba4ac040f82bc2ef6e6b500483975c4ebacd34bec945fda12"}, + {file = "pandas-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6f3bf5ec947526106399a9e1d26d40ee2b259c66422efdf4de63c848492d91bb"}, + {file = "pandas-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:1c78cf43c8fde236342a1cb2c34bcff89564a7bfed7e474ed2fffa6aed03a956"}, + {file = "pandas-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8dfc17328e8da77be3cf9f47509e5637ba8f137148ed0e9b5241e1baf526e20a"}, + {file = "pandas-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:ec6c851509364c59a5344458ab935e6451b31b818be467eb24b0fe89bd05b6b9"}, + {file = "pandas-2.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:911580460fc4884d9b05254b38a6bfadddfcc6aaef856fb5859e7ca202e45275"}, + {file = "pandas-2.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f4d6feeba91744872a600e6edbbd5b033005b431d5ae8379abee5bcfa479fab"}, + {file = "pandas-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fe37e757f462d31a9cd7580236a82f353f5713a80e059a29753cf938c6775d96"}, + {file = "pandas-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5db9637dbc24b631ff3707269ae4559bce4b7fd75c1c4d7e13f40edc42df4444"}, + {file = "pandas-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4645f770f98d656f11c69e81aeb21c6fca076a44bed3dcbb9396a4311bc7f6d8"}, + {file = "pandas-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:342e59589cc454aaff7484d75b816a433350b3d7964d7847327edda4d532a2e3"}, + {file = "pandas-2.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d12f618d80379fde6af007f65f0c25bd3e40251dbd1636480dfffce2cf1e6da"}, + {file = "pandas-2.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd71c47a911da120d72ef173aeac0bf5241423f9bfea57320110a978457e069e"}, + {file = "pandas-2.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:09e3b1587f0f3b0913e21e8b32c3119174551deb4a4eba4a89bc7377947977e7"}, + {file = "pandas-2.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2323294c73ed50f612f67e2bf3ae45aea04dce5690778e08a09391897f35ff88"}, + {file = "pandas-2.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:b4b0de34dc8499c2db34000ef8baad684cfa4cbd836ecee05f323ebfba348c7d"}, + {file = "pandas-2.3.1.tar.gz", hash = "sha256:0a95b9ac964fe83ce317827f80304d37388ea77616b1425f0ae41c9d2d0d7bb2"}, ] [package.dependencies] numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, {version = ">=1.26.0", markers = "python_version >= \"3.12\""}, {version = ">=1.23.2", markers = "python_version == \"3.11\""}, - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -4622,104 +4736,140 @@ ptyprocess = ">=0.5" [[package]] name = "pillow" -version = "11.1.0" +version = "11.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8"}, - {file = "pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07"}, - {file = "pillow-11.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482"}, - {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e"}, - {file = "pillow-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269"}, - {file = "pillow-11.1.0-cp310-cp310-win32.whl", hash = "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49"}, - {file = "pillow-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a"}, - {file = "pillow-11.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65"}, - {file = "pillow-11.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e06695e0326d05b06833b40b7ef477e475d0b1ba3a6d27da1bb48c23209bf457"}, - {file = "pillow-11.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96f82000e12f23e4f29346e42702b6ed9a2f2fea34a740dd5ffffcc8c539eb35"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3cd561ded2cf2bbae44d4605837221b987c216cff94f49dfeed63488bb228d2"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f189805c8be5ca5add39e6f899e6ce2ed824e65fb45f3c28cb2841911da19070"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dd0052e9db3474df30433f83a71b9b23bd9e4ef1de13d92df21a52c0303b8ab6"}, - {file = "pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:837060a8599b8f5d402e97197d4924f05a2e0d68756998345c829c33186217b1"}, - {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:aa8dd43daa836b9a8128dbe7d923423e5ad86f50a7a14dc688194b7be5c0dea2"}, - {file = "pillow-11.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96"}, - {file = "pillow-11.1.0-cp311-cp311-win32.whl", hash = "sha256:c12fc111ef090845de2bb15009372175d76ac99969bdf31e2ce9b42e4b8cd88f"}, - {file = "pillow-11.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761"}, - {file = "pillow-11.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:f7955ecf5609dee9442cbface754f2c6e541d9e6eda87fad7f7a989b0bdb9d71"}, - {file = "pillow-11.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2062ffb1d36544d42fcaa277b069c88b01bb7298f4efa06731a7fd6cc290b81a"}, - {file = "pillow-11.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a85b653980faad27e88b141348707ceeef8a1186f75ecc600c395dcac19f385b"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9409c080586d1f683df3f184f20e36fb647f2e0bc3988094d4fd8c9f4eb1b3b3"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fdadc077553621911f27ce206ffcbec7d3f8d7b50e0da39f10997e8e2bb7f6a"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:93a18841d09bcdd774dcdc308e4537e1f867b3dec059c131fde0327899734aa1"}, - {file = "pillow-11.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9aa9aeddeed452b2f616ff5507459e7bab436916ccb10961c4a382cd3e03f47f"}, - {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3cdcdb0b896e981678eee140d882b70092dac83ac1cdf6b3a60e2216a73f2b91"}, - {file = "pillow-11.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:36ba10b9cb413e7c7dfa3e189aba252deee0602c86c309799da5a74009ac7a1c"}, - {file = "pillow-11.1.0-cp312-cp312-win32.whl", hash = "sha256:cfd5cd998c2e36a862d0e27b2df63237e67273f2fc78f47445b14e73a810e7e6"}, - {file = "pillow-11.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:a697cd8ba0383bba3d2d3ada02b34ed268cb548b369943cd349007730c92bddf"}, - {file = "pillow-11.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:4dd43a78897793f60766563969442020e90eb7847463eca901e41ba186a7d4a5"}, - {file = "pillow-11.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ae98e14432d458fc3de11a77ccb3ae65ddce70f730e7c76140653048c71bfcbc"}, - {file = "pillow-11.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cc1331b6d5a6e144aeb5e626f4375f5b7ae9934ba620c0ac6b3e43d5e683a0f0"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:758e9d4ef15d3560214cddbc97b8ef3ef86ce04d62ddac17ad39ba87e89bd3b1"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b523466b1a31d0dcef7c5be1f20b942919b62fd6e9a9be199d035509cbefc0ec"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:9044b5e4f7083f209c4e35aa5dd54b1dd5b112b108648f5c902ad586d4f945c5"}, - {file = "pillow-11.1.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3764d53e09cdedd91bee65c2527815d315c6b90d7b8b79759cc48d7bf5d4f114"}, - {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31eba6bbdd27dde97b0174ddf0297d7a9c3a507a8a1480e1e60ef914fe23d352"}, - {file = "pillow-11.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b5d658fbd9f0d6eea113aea286b21d3cd4d3fd978157cbf2447a6035916506d3"}, - {file = "pillow-11.1.0-cp313-cp313-win32.whl", hash = "sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9"}, - {file = "pillow-11.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:593c5fd6be85da83656b93ffcccc2312d2d149d251e98588b14fbc288fd8909c"}, - {file = "pillow-11.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:11633d58b6ee5733bde153a8dafd25e505ea3d32e261accd388827ee987baf65"}, - {file = "pillow-11.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:70ca5ef3b3b1c4a0812b5c63c57c23b63e53bc38e758b37a951e5bc466449861"}, - {file = "pillow-11.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8000376f139d4d38d6851eb149b321a52bb8893a88dae8ee7d95840431977081"}, - {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ee85f0696a17dd28fbcfceb59f9510aa71934b483d1f5601d1030c3c8304f3c"}, - {file = "pillow-11.1.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:dd0e081319328928531df7a0e63621caf67652c8464303fd102141b785ef9547"}, - {file = "pillow-11.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e63e4e5081de46517099dc30abe418122f54531a6ae2ebc8680bcd7096860eab"}, - {file = "pillow-11.1.0-cp313-cp313t-win32.whl", hash = "sha256:dda60aa465b861324e65a78c9f5cf0f4bc713e4309f83bc387be158b077963d9"}, - {file = "pillow-11.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ad5db5781c774ab9a9b2c4302bbf0c1014960a0a7be63278d13ae6fdf88126fe"}, - {file = "pillow-11.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:67cd427c68926108778a9005f2a04adbd5e67c442ed21d95389fe1d595458756"}, - {file = "pillow-11.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:bf902d7413c82a1bfa08b06a070876132a5ae6b2388e2712aab3a7cbc02205c6"}, - {file = "pillow-11.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c1eec9d950b6fe688edee07138993e54ee4ae634c51443cfb7c1e7613322718e"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e275ee4cb11c262bd108ab2081f750db2a1c0b8c12c1897f27b160c8bd57bbc"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4db853948ce4e718f2fc775b75c37ba2efb6aaea41a1a5fc57f0af59eee774b2"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ab8a209b8485d3db694fa97a896d96dd6533d63c22829043fd9de627060beade"}, - {file = "pillow-11.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:54251ef02a2309b5eec99d151ebf5c9904b77976c8abdcbce7891ed22df53884"}, - {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5bb94705aea800051a743aa4874bb1397d4695fb0583ba5e425ee0328757f196"}, - {file = "pillow-11.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89dbdb3e6e9594d512780a5a1c42801879628b38e3efc7038094430844e271d8"}, - {file = "pillow-11.1.0-cp39-cp39-win32.whl", hash = "sha256:e5449ca63da169a2e6068dd0e2fcc8d91f9558aba89ff6d02121ca8ab11e79e5"}, - {file = "pillow-11.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:3362c6ca227e65c54bf71a5f88b3d4565ff1bcbc63ae72c34b07bbb1cc59a43f"}, - {file = "pillow-11.1.0-cp39-cp39-win_arm64.whl", hash = "sha256:b20be51b37a75cc54c2c55def3fa2c65bb94ba859dde241cd0a4fd302de5ae0a"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73"}, - {file = "pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0"}, - {file = "pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20"}, -] - -[package.extras] -docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] + {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, + {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7107195ddc914f656c7fc8e4a5e1c25f32e9236ea3ea860f257b0436011fddd0"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc3e831b563b3114baac7ec2ee86819eb03caa1a2cef0b481a5675b59c4fe23b"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1f182ebd2303acf8c380a54f615ec883322593320a9b00438eb842c1f37ae50"}, + {file = "pillow-11.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4445fa62e15936a028672fd48c4c11a66d641d2c05726c7ec1f8ba6a572036ae"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71f511f6b3b91dd543282477be45a033e4845a40278fa8dcdbfdb07109bf18f9"}, + {file = "pillow-11.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040a5b691b0713e1f6cbe222e0f4f74cd233421e105850ae3b3c0ceda520f42e"}, + {file = "pillow-11.3.0-cp310-cp310-win32.whl", hash = "sha256:89bd777bc6624fe4115e9fac3352c79ed60f3bb18651420635f26e643e3dd1f6"}, + {file = "pillow-11.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:19d2ff547c75b8e3ff46f4d9ef969a06c30ab2d4263a9e287733aa8b2429ce8f"}, + {file = "pillow-11.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:819931d25e57b513242859ce1876c58c59dc31587847bf74cfe06b2e0cb22d2f"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722"}, + {file = "pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58"}, + {file = "pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e"}, + {file = "pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94"}, + {file = "pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0"}, + {file = "pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac"}, + {file = "pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4"}, + {file = "pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7"}, + {file = "pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809"}, + {file = "pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d"}, + {file = "pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149"}, + {file = "pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d"}, + {file = "pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8"}, + {file = "pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c"}, + {file = "pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805"}, + {file = "pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2"}, + {file = "pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b"}, + {file = "pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3"}, + {file = "pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51"}, + {file = "pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e"}, + {file = "pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8"}, + {file = "pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe"}, + {file = "pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c"}, + {file = "pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788"}, + {file = "pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31"}, + {file = "pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12"}, + {file = "pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027"}, + {file = "pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874"}, + {file = "pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a"}, + {file = "pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214"}, + {file = "pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635"}, + {file = "pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae"}, + {file = "pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b"}, + {file = "pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50"}, + {file = "pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b"}, + {file = "pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12"}, + {file = "pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db"}, + {file = "pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:48d254f8a4c776de343051023eb61ffe818299eeac478da55227d96e241de53f"}, + {file = "pillow-11.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7aee118e30a4cf54fdd873bd3a29de51e29105ab11f9aad8c32123f58c8f8081"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:23cff760a9049c502721bdb743a7cb3e03365fafcdfc2ef9784610714166e5a4"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6359a3bc43f57d5b375d1ad54a0074318a0844d11b76abccf478c37c986d3cfc"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:092c80c76635f5ecb10f3f83d76716165c96f5229addbd1ec2bdbbda7d496e06"}, + {file = "pillow-11.3.0-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cadc9e0ea0a2431124cde7e1697106471fc4c1da01530e679b2391c37d3fbb3a"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6a418691000f2a418c9135a7cf0d797c1bb7d9a485e61fe8e7722845b95ef978"}, + {file = "pillow-11.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:97afb3a00b65cc0804d1c7abddbf090a81eaac02768af58cbdcaaa0a931e0b6d"}, + {file = "pillow-11.3.0-cp39-cp39-win32.whl", hash = "sha256:ea944117a7974ae78059fcc1800e5d3295172bb97035c0c1d9345fca1419da71"}, + {file = "pillow-11.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e5c5858ad8ec655450a7c7df532e9842cf8df7cc349df7225c60d5d348c8aada"}, + {file = "pillow-11.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:6abdbfd3aea42be05702a8dd98832329c167ee84400a1d1f61ab11437f1717eb"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3cee80663f29e3843b68199b9d6f4f54bd1d4a6b59bdd91bceefc51238bcb967"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b5f56c3f344f2ccaf0dd875d3e180f631dc60a51b314295a3e681fe8cf851fbe"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e67d793d180c9df62f1f40aee3accca4829d3794c95098887edc18af4b8b780c"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d000f46e2917c705e9fb93a3606ee4a819d1e3aa7a9b442f6444f07e77cf5e25"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:527b37216b6ac3a12d7838dc3bd75208ec57c1c6d11ef01902266a5a0c14fc27"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:be5463ac478b623b9dd3937afd7fb7ab3d79dd290a28e2b6df292dc75063eb8a"}, + {file = "pillow-11.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:8dc70ca24c110503e16918a658b869019126ecfe03109b754c402daff12b3d9f"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7"}, + {file = "pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8"}, + {file = "pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-inline-tabs", "sphinxext-opengraph"] fpx = ["olefile"] mic = ["olefile"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"] +test-arrow = ["pyarrow"] +tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] typing = ["typing-extensions ; python_version < \"3.10\""] xmp = ["defusedxml"] [[package]] name = "platformdirs" -version = "4.3.7" +version = "4.3.8" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "platformdirs-4.3.7-py3-none-any.whl", hash = "sha256:a03875334331946f13c549dbd8f4bac7a13a50a895a0eb1e8c6a8ace80d40a94"}, - {file = "platformdirs-4.3.7.tar.gz", hash = "sha256:eb437d586b6a0986388f0d6f74aa0cde27b48d0e3d66843640bfb6bdcdb6e351"}, + {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, + {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, ] [package.extras] @@ -4729,20 +4879,20 @@ type = ["mypy (>=1.14.1)"] [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pre-commit" @@ -4766,15 +4916,15 @@ virtualenv = ">=20.10.0" [[package]] name = "prometheus-client" -version = "0.21.1" +version = "0.22.1" description = "Python client for the Prometheus monitoring system." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301"}, - {file = "prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb"}, + {file = "prometheus_client-0.22.1-py3-none-any.whl", hash = "sha256:cca895342e308174341b2cbf99a56bef291fbc0ef7b9e5412a0f26d653ba7094"}, + {file = "prometheus_client-0.22.1.tar.gz", hash = "sha256:190f1331e783cf21eb60bca559354e0a4d4378facecf78f5428c39b675d20d28"}, ] [package.extras] @@ -4782,15 +4932,15 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.50" +version = "3.0.51" description = "Library for building powerful interactive command lines in Python" optional = true -python-versions = ">=3.8.0" +python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198"}, - {file = "prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab"}, + {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, + {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, ] [package.dependencies] @@ -4798,21 +4948,21 @@ wcwidth = "*" [[package]] name = "protobuf" -version = "6.30.1" +version = "6.31.1" description = "" optional = true python-versions = ">=3.9" groups = ["main"] files = [ - {file = "protobuf-6.30.1-cp310-abi3-win32.whl", hash = "sha256:ba0706f948d0195f5cac504da156d88174e03218d9364ab40d903788c1903d7e"}, - {file = "protobuf-6.30.1-cp310-abi3-win_amd64.whl", hash = "sha256:ed484f9ddd47f0f1bf0648806cccdb4fe2fb6b19820f9b79a5adf5dcfd1b8c5f"}, - {file = "protobuf-6.30.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aa4f7dfaed0d840b03d08d14bfdb41348feaee06a828a8c455698234135b4075"}, - {file = "protobuf-6.30.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:47cd320b7db63e8c9ac35f5596ea1c1e61491d8a8eb6d8b45edc44760b53a4f6"}, - {file = "protobuf-6.30.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:e3083660225fa94748ac2e407f09a899e6a28bf9c0e70c75def8d15706bf85fc"}, - {file = "protobuf-6.30.1-cp39-cp39-win32.whl", hash = "sha256:554d7e61cce2aa4c63ca27328f757a9f3867bce8ec213bf09096a8d16bcdcb6a"}, - {file = "protobuf-6.30.1-cp39-cp39-win_amd64.whl", hash = "sha256:b510f55ce60f84dc7febc619b47215b900466e3555ab8cb1ba42deb4496d6cc0"}, - {file = "protobuf-6.30.1-py3-none-any.whl", hash = "sha256:3c25e51e1359f1f5fa3b298faa6016e650d148f214db2e47671131b9063c53be"}, - {file = "protobuf-6.30.1.tar.gz", hash = "sha256:535fb4e44d0236893d5cf1263a0f706f1160b689a7ab962e9da8a9ce4050b780"}, + {file = "protobuf-6.31.1-cp310-abi3-win32.whl", hash = "sha256:7fa17d5a29c2e04b7d90e5e32388b8bfd0e7107cd8e616feef7ed3fa6bdab5c9"}, + {file = "protobuf-6.31.1-cp310-abi3-win_amd64.whl", hash = "sha256:426f59d2964864a1a366254fa703b8632dcec0790d8862d30034d8245e1cd447"}, + {file = "protobuf-6.31.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:6f1227473dc43d44ed644425268eb7c2e488ae245d51c6866d19fe158e207402"}, + {file = "protobuf-6.31.1-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:a40fc12b84c154884d7d4c4ebd675d5b3b5283e155f324049ae396b95ddebc39"}, + {file = "protobuf-6.31.1-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:4ee898bf66f7a8b0bd21bce523814e6fbd8c6add948045ce958b73af7e8878c6"}, + {file = "protobuf-6.31.1-cp39-cp39-win32.whl", hash = "sha256:0414e3aa5a5f3ff423828e1e6a6e907d6c65c1d5b7e6e975793d5590bdeecc16"}, + {file = "protobuf-6.31.1-cp39-cp39-win_amd64.whl", hash = "sha256:8764cf4587791e7564051b35524b72844f845ad0bb011704c3736cce762d8fe9"}, + {file = "protobuf-6.31.1-py3-none-any.whl", hash = "sha256:720a6c7e6b77288b85063569baae8536671b39f15cc22037ec7045658d80489e"}, + {file = "protobuf-6.31.1.tar.gz", hash = "sha256:d8cac4c982f0b957a4dc73a80e2ea24fab08e679c0de9deb835f4a12d69aca9a"}, ] [[package]] @@ -4847,7 +4997,7 @@ description = "Run a subprocess in a pseudo terminal" optional = true python-versions = "*" groups = ["main"] -markers = "(extra == \"dev\" or extra == \"docs\") and (sys_platform != \"win32\" or os_name != \"nt\") and (sys_platform != \"win32\" and sys_platform != \"emscripten\" or os_name != \"nt\" or python_version < \"3.10\")" +markers = "(extra == \"dev\" or extra == \"docs\") and (sys_platform != \"win32\" or os_name != \"nt\") and (sys_platform != \"win32\" and sys_platform != \"emscripten\" or python_version < \"3.10\" or os_name != \"nt\")" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -4900,20 +5050,21 @@ files = [ [[package]] name = "pydantic" -version = "2.10.6" +version = "2.11.7" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, - {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, + {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"}, + {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.27.2" +pydantic-core = "2.33.2" typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -4921,139 +5072,116 @@ timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows [[package]] name = "pydantic-core" -version = "2.27.2" +version = "2.33.2" description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, - {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, ] [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" -[[package]] -name = "pydantic-settings" -version = "2.8.1" -description = "Settings management using Pydantic" -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c"}, - {file = "pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585"}, -] - -[package.dependencies] -pydantic = ">=2.7.0" -python-dotenv = ">=0.21.0" - -[package.extras] -azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] -toml = ["tomli (>=2.0.1)"] -yaml = ["pyyaml (>=6.0.1)"] - [[package]] name = "pydata-sphinx-theme" version = "0.15.4" @@ -5104,14 +5232,14 @@ numpy = "*" [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, - {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -5137,24 +5265,24 @@ tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] [[package]] name = "pylint" -version = "3.3.6" +version = "3.3.7" description = "python code static checker" optional = true python-versions = ">=3.9.0" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "pylint-3.3.6-py3-none-any.whl", hash = "sha256:8b7c2d3e86ae3f94fb27703d521dd0b9b6b378775991f504d7c3a6275aa0a6a6"}, - {file = "pylint-3.3.6.tar.gz", hash = "sha256:b634a041aac33706d56a0d217e6587228c66427e20ec21a019bc4cdee48c040a"}, + {file = "pylint-3.3.7-py3-none-any.whl", hash = "sha256:43860aafefce92fca4cf6b61fe199cdc5ae54ea28f9bf4cd49de267b5195803d"}, + {file = "pylint-3.3.7.tar.gz", hash = "sha256:2b11de8bde49f9c5059452e0c310c079c746a0a8eeaa789e5aa966ecc23e4559"}, ] [package.dependencies] astroid = ">=3.3.8,<=3.4.0.dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ - {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, + {version = ">=0.3.6", markers = "python_version == \"3.11\""}, ] isort = ">=4.2.5,<5.13 || >5.13,<7" mccabe = ">=0.6,<0.8" @@ -5169,14 +5297,14 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" -version = "3.2.1" +version = "3.2.3" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1"}, - {file = "pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a"}, + {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"}, + {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"}, ] [package.extras] @@ -5184,24 +5312,24 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pyproject-api" -version = "1.9.0" +version = "1.9.1" description = "API to interact with the python pyproject.toml based projects" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pyproject_api-1.9.0-py3-none-any.whl", hash = "sha256:326df9d68dea22d9d98b5243c46e3ca3161b07a1b9b18e213d1e24fd0e605766"}, - {file = "pyproject_api-1.9.0.tar.gz", hash = "sha256:7e8a9854b2dfb49454fae421cb86af43efbb2b2454e5646ffb7623540321ae6e"}, + {file = "pyproject_api-1.9.1-py3-none-any.whl", hash = "sha256:7d6238d92f8962773dd75b5f0c4a6a27cce092a14b623b811dba656f3b628948"}, + {file = "pyproject_api-1.9.1.tar.gz", hash = "sha256:43c9918f49daab37e302038fc1aed54a8c7a91a9fa935d00b9a485f37e0f5335"}, ] [package.dependencies] -packaging = ">=24.2" +packaging = ">=25" tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx-autodoc-typehints (>=3)"] -testing = ["covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "setuptools (>=75.8)"] +docs = ["furo (>=2024.8.6)", "sphinx-autodoc-typehints (>=3.2)"] +testing = ["covdefaults (>=2.3)", "pytest (>=8.3.5)", "pytest-cov (>=6.1.1)", "pytest-mock (>=3.14)", "setuptools (>=80.3.1)"] [[package]] name = "pyroots" @@ -5242,44 +5370,46 @@ test = ["alabaster (==0.7.12)", "attrs (==18.1.0)", "babel (==2.6.0)", "backcall [[package]] name = "pytest" -version = "8.3.5" +version = "8.4.1" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820"}, - {file = "pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845"}, + {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, + {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, ] [package.dependencies] -colorama = {version = "*", markers = "sys_platform == \"win32\""} -exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -iniconfig = "*" -packaging = "*" +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" pluggy = ">=1.5,<2" +pygments = ">=2.7.2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-cov" -version = "6.0.0" +version = "6.2.1" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, - {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, + {file = "pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5"}, + {file = "pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2"}, ] [package.dependencies] coverage = {version = ">=7.5", extras = ["toml"]} -pytest = ">=4.6" +pluggy = ">=1.2" +pytest = ">=6.2.5" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] @@ -5306,15 +5436,15 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] [[package]] name = "pytest-timeout" -version = "2.3.1" +version = "2.4.0" description = "pytest plugin to abort hanging tests" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest-timeout-2.3.1.tar.gz", hash = "sha256:12397729125c6ecbdaca01035b9e5239d4db97352320af155b3f5de1ba5165d9"}, - {file = "pytest_timeout-2.3.1-py3-none-any.whl", hash = "sha256:68188cb703edfc6a18fad98dc25a3c61e9f24d644b0b70f33af545219fc7813e"}, + {file = "pytest_timeout-2.4.0-py3-none-any.whl", hash = "sha256:c42667e5cdadb151aeb5b26d114aff6bdf5a907f176a007a30b940d3d865b5c2"}, + {file = "pytest_timeout-2.4.0.tar.gz", hash = "sha256:7e68e90b01f9eff71332b25001f85c75495fc4e3a836701876183c4bcfd0540a"}, ] [package.dependencies] @@ -5322,15 +5452,15 @@ pytest = ">=7.0.0" [[package]] name = "pytest-xdist" -version = "3.6.1" +version = "3.8.0" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7"}, - {file = "pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d"}, + {file = "pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88"}, + {file = "pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1"}, ] [package.dependencies] @@ -5357,22 +5487,6 @@ files = [ [package.dependencies] six = ">=1.5" -[[package]] -name = "python-dotenv" -version = "1.0.1" -description = "Read key-value pairs from a .env file and set them as environment variables" -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, - {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, -] - -[package.extras] -cli = ["click (>=5.0)"] - [[package]] name = "python-json-logger" version = "3.3.0" @@ -5394,14 +5508,14 @@ dev = ["backports.zoneinfo ; python_version < \"3.9\"", "black", "build", "freez [[package]] name = "pytz" -version = "2025.1" +version = "2025.2" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"}, - {file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"}, + {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, + {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, ] [[package]] @@ -5514,127 +5628,97 @@ files = [ [[package]] name = "pyzmq" -version = "26.3.0" +version = "27.0.0" description = "Python bindings for 0MQ" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "pyzmq-26.3.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:1586944f4736515af5c6d3a5b150c7e8ca2a2d6e46b23057320584d6f2438f4a"}, - {file = "pyzmq-26.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa7efc695d1fc9f72d91bf9b6c6fe2d7e1b4193836ec530a98faf7d7a7577a58"}, - {file = "pyzmq-26.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bd84441e4021cec6e4dd040550386cd9c9ea1d9418ea1a8002dbb7b576026b2b"}, - {file = "pyzmq-26.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9176856f36c34a8aa5c0b35ddf52a5d5cd8abeece57c2cd904cfddae3fd9acd3"}, - {file = "pyzmq-26.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:49334faa749d55b77f084389a80654bf2e68ab5191c0235066f0140c1b670d64"}, - {file = "pyzmq-26.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fd30fc80fe96efb06bea21667c5793bbd65c0dc793187feb39b8f96990680b00"}, - {file = "pyzmq-26.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b2eddfbbfb473a62c3a251bb737a6d58d91907f6e1d95791431ebe556f47d916"}, - {file = "pyzmq-26.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:70b3acb9ad729a53d4e751dace35404a024f188aad406013454216aba5485b4e"}, - {file = "pyzmq-26.3.0-cp310-cp310-win32.whl", hash = "sha256:c1bd75d692cd7c6d862a98013bfdf06702783b75cffbf5dae06d718fecefe8f2"}, - {file = "pyzmq-26.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:d7165bcda0dbf203e5ad04d79955d223d84b2263df4db92f525ba370b03a12ab"}, - {file = "pyzmq-26.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:e34a63f71d2ecffb3c643909ad2d488251afeb5ef3635602b3448e609611a7ed"}, - {file = "pyzmq-26.3.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:2833602d9d42c94b9d0d2a44d2b382d3d3a4485be018ba19dddc401a464c617a"}, - {file = "pyzmq-26.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8270d104ec7caa0bdac246d31d48d94472033ceab5ba142881704350b28159c"}, - {file = "pyzmq-26.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c208a977843d18d3bd185f323e4eaa912eb4869cb230947dc6edd8a27a4e558a"}, - {file = "pyzmq-26.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eddc2be28a379c218e0d92e4a432805dcb0ca5870156a90b54c03cd9799f9f8a"}, - {file = "pyzmq-26.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c0b519fa2159c42272f8a244354a0e110d65175647e5185b04008ec00df9f079"}, - {file = "pyzmq-26.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1595533de3a80bf8363372c20bafa963ec4bf9f2b8f539b1d9a5017f430b84c9"}, - {file = "pyzmq-26.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bbef99eb8d18ba9a40f00e8836b8040cdcf0f2fa649684cf7a66339599919d21"}, - {file = "pyzmq-26.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:979486d444ca3c469cd1c7f6a619ce48ff08b3b595d451937db543754bfacb65"}, - {file = "pyzmq-26.3.0-cp311-cp311-win32.whl", hash = "sha256:4b127cfe10b4c56e4285b69fd4b38ea1d368099ea4273d8fb349163fce3cd598"}, - {file = "pyzmq-26.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cf736cc1298ef15280d9fcf7a25c09b05af016656856dc6fe5626fd8912658dd"}, - {file = "pyzmq-26.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:2dc46ec09f5d36f606ac8393303149e69d17121beee13c8dac25e2a2078e31c4"}, - {file = "pyzmq-26.3.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:c80653332c6136da7f4d4e143975e74ac0fa14f851f716d90583bc19e8945cea"}, - {file = "pyzmq-26.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e317ee1d4528a03506cb1c282cd9db73660a35b3564096de37de7350e7d87a7"}, - {file = "pyzmq-26.3.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:943a22ebb3daacb45f76a9bcca9a7b74e7d94608c0c0505da30af900b998ca8d"}, - {file = "pyzmq-26.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fc9e71490d989144981ea21ef4fdfaa7b6aa84aff9632d91c736441ce2f6b00"}, - {file = "pyzmq-26.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e281a8071a06888575a4eb523c4deeefdcd2f5fe4a2d47e02ac8bf3a5b49f695"}, - {file = "pyzmq-26.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:be77efd735bb1064605be8dec6e721141c1421ef0b115ef54e493a64e50e9a52"}, - {file = "pyzmq-26.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7a4ac2ffa34f1212dd586af90f4ba894e424f0cabb3a49cdcff944925640f6ac"}, - {file = "pyzmq-26.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ba698c7c252af83b6bba9775035263f0df5f807f0404019916d4b71af8161f66"}, - {file = "pyzmq-26.3.0-cp312-cp312-win32.whl", hash = "sha256:214038aaa88e801e54c2ef0cfdb2e6df27eb05f67b477380a452b595c5ecfa37"}, - {file = "pyzmq-26.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:bad7fe0372e505442482ca3ccbc0d6f38dae81b1650f57a0aa6bbee18e7df495"}, - {file = "pyzmq-26.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:b7b578d604e79e99aa39495becea013fd043fa9f36e4b490efa951f3d847a24d"}, - {file = "pyzmq-26.3.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:fa85953df84beb7b8b73cb3ec3f5d92b62687a09a8e71525c6734e020edf56fd"}, - {file = "pyzmq-26.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:209d09f0ab6ddbcebe64630d1e6ca940687e736f443c265ae15bc4bfad833597"}, - {file = "pyzmq-26.3.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d35cc1086f1d4f907df85c6cceb2245cb39a04f69c3f375993363216134d76d4"}, - {file = "pyzmq-26.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b380e9087078ba91e45fb18cdd0c25275ffaa045cf63c947be0ddae6186bc9d9"}, - {file = "pyzmq-26.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:6d64e74143587efe7c9522bb74d1448128fdf9897cc9b6d8b9927490922fd558"}, - {file = "pyzmq-26.3.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:efba4f53ac7752eea6d8ca38a4ddac579e6e742fba78d1e99c12c95cd2acfc64"}, - {file = "pyzmq-26.3.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:9b0137a1c40da3b7989839f9b78a44de642cdd1ce20dcef341de174c8d04aa53"}, - {file = "pyzmq-26.3.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:a995404bd3982c089e57b428c74edd5bfc3b0616b3dbcd6a8e270f1ee2110f36"}, - {file = "pyzmq-26.3.0-cp313-cp313-win32.whl", hash = "sha256:240b1634b9e530ef6a277d95cbca1a6922f44dfddc5f0a3cd6c722a8de867f14"}, - {file = "pyzmq-26.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:fe67291775ea4c2883764ba467eb389c29c308c56b86c1e19e49c9e1ed0cbeca"}, - {file = "pyzmq-26.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:73ca9ae9a9011b714cf7650450cd9c8b61a135180b708904f1f0a05004543dce"}, - {file = "pyzmq-26.3.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:fea7efbd7e49af9d7e5ed6c506dfc7de3d1a628790bd3a35fd0e3c904dc7d464"}, - {file = "pyzmq-26.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4430c7cba23bb0e2ee203eee7851c1654167d956fc6d4b3a87909ccaf3c5825"}, - {file = "pyzmq-26.3.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:016d89bee8c7d566fad75516b4e53ec7c81018c062d4c51cd061badf9539be52"}, - {file = "pyzmq-26.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04bfe59852d76d56736bfd10ac1d49d421ab8ed11030b4a0332900691507f557"}, - {file = "pyzmq-26.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:1fe05bd0d633a0f672bb28cb8b4743358d196792e1caf04973b7898a0d70b046"}, - {file = "pyzmq-26.3.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:2aa1a9f236d5b835fb8642f27de95f9edcfd276c4bc1b6ffc84f27c6fb2e2981"}, - {file = "pyzmq-26.3.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:21399b31753bf321043ea60c360ed5052cc7be20739785b1dff1820f819e35b3"}, - {file = "pyzmq-26.3.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:d015efcd96aca8882057e7e6f06224f79eecd22cad193d3e6a0a91ec67590d1f"}, - {file = "pyzmq-26.3.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:18183cc3851b995fdc7e5f03d03b8a4e1b12b0f79dff1ec1da75069af6357a05"}, - {file = "pyzmq-26.3.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:da87e977f92d930a3683e10ba2b38bcc59adfc25896827e0b9d78b208b7757a6"}, - {file = "pyzmq-26.3.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cf6db401f4957afbf372a4730c6d5b2a234393af723983cbf4bcd13d54c71e1a"}, - {file = "pyzmq-26.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03caa2ffd64252122139d50ec92987f89616b9b92c9ba72920b40e92709d5e26"}, - {file = "pyzmq-26.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fbf206e5329e20937fa19bd41cf3af06d5967f8f7e86b59d783b26b40ced755c"}, - {file = "pyzmq-26.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6fb539a6382a048308b409d8c66d79bf636eda1b24f70c78f2a1fd16e92b037b"}, - {file = "pyzmq-26.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7897b8c8bbbb2bd8cad887bffcb07aede71ef1e45383bd4d6ac049bf0af312a4"}, - {file = "pyzmq-26.3.0-cp38-cp38-win32.whl", hash = "sha256:91dead2daca698ae52ce70ee2adbb94ddd9b5f96877565fd40aa4efd18ecc6a3"}, - {file = "pyzmq-26.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:8c088e009a6d6b9f563336adb906e3a8d3fd64db129acc8d8fd0e9fe22b2dac8"}, - {file = "pyzmq-26.3.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2eaed0d911fb3280981d5495978152fab6afd9fe217fd16f411523665089cef1"}, - {file = "pyzmq-26.3.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7998b60ef1c105846fb3bfca494769fde3bba6160902e7cd27a8df8257890ee9"}, - {file = "pyzmq-26.3.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:96c0006a8d1d00e46cb44c8e8d7316d4a232f3d8f2ed43179d4578dbcb0829b6"}, - {file = "pyzmq-26.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e17cc198dc50a25a0f245e6b1e56f692df2acec3ccae82d1f60c34bfb72bbec"}, - {file = "pyzmq-26.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:92a30840f4f2a31f7049d0a7de5fc69dd03b19bd5d8e7fed8d0bde49ce49b589"}, - {file = "pyzmq-26.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f52eba83272a26b444f4b8fc79f2e2c83f91d706d693836c9f7ccb16e6713c31"}, - {file = "pyzmq-26.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:952085a09ff32115794629ba47f8940896d7842afdef1283332109d38222479d"}, - {file = "pyzmq-26.3.0-cp39-cp39-win32.whl", hash = "sha256:0240289e33e3fbae44a5db73e54e955399179332a6b1d47c764a4983ec1524c3"}, - {file = "pyzmq-26.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:b2db7c82f08b8ce44c0b9d1153ce63907491972a7581e8b6adea71817f119df8"}, - {file = "pyzmq-26.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:2d3459b6311463c96abcb97808ee0a1abb0d932833edb6aa81c30d622fd4a12d"}, - {file = "pyzmq-26.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ad03f4252d9041b0635c37528dfa3f44b39f46024ae28c8567f7423676ee409b"}, - {file = "pyzmq-26.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f3dfb68cf7bf4cfdf34283a75848e077c5defa4907506327282afe92780084d"}, - {file = "pyzmq-26.3.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:356ec0e39c5a9cda872b65aca1fd8a5d296ffdadf8e2442b70ff32e73ef597b1"}, - {file = "pyzmq-26.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:749d671b0eec8e738bbf0b361168369d8c682b94fcd458c20741dc4d69ef5278"}, - {file = "pyzmq-26.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f950f17ae608e0786298340163cac25a4c5543ef25362dd5ddb6dcb10b547be9"}, - {file = "pyzmq-26.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b4fc9903a73c25be9d5fe45c87faababcf3879445efa16140146b08fccfac017"}, - {file = "pyzmq-26.3.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c15b69af22030960ac63567e98ad8221cddf5d720d9cf03d85021dfd452324ef"}, - {file = "pyzmq-26.3.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2cf9ab0dff4dbaa2e893eb608373c97eb908e53b7d9793ad00ccbd082c0ee12f"}, - {file = "pyzmq-26.3.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ec332675f6a138db57aad93ae6387953763f85419bdbd18e914cb279ee1c451"}, - {file = "pyzmq-26.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:eb96568a22fe070590942cd4780950e2172e00fb033a8b76e47692583b1bd97c"}, - {file = "pyzmq-26.3.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:009a38241c76184cb004c869e82a99f0aee32eda412c1eb44df5820324a01d25"}, - {file = "pyzmq-26.3.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c22a12713707467abedc6d75529dd365180c4c2a1511268972c6e1d472bd63e"}, - {file = "pyzmq-26.3.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1614fcd116275d24f2346ffca4047a741c546ad9d561cbf7813f11226ca4ed2c"}, - {file = "pyzmq-26.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e2cafe7e9c7fed690e8ecf65af119f9c482923b5075a78f6f7629c63e1b4b1d"}, - {file = "pyzmq-26.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:14e0b81753424bd374075df6cc30b87f2c99e5f022501d97eff66544ca578941"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:21c6ddb98557a77cfe3366af0c5600fb222a1b2de5f90d9cd052b324e0c295e8"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc81d5d60c9d40e692de14b8d884d43cf67562402b931681f0ccb3ce6b19875"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52b064fafef772d0f5dbf52d4c39f092be7bc62d9a602fe6e82082e001326de3"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b72206eb041f780451c61e1e89dbc3705f3d66aaaa14ee320d4f55864b13358a"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ab78dc21c7b1e13053086bcf0b4246440b43b5409904b73bfd1156654ece8a1"}, - {file = "pyzmq-26.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0b42403ad7d1194dca9574cd3c56691c345f4601fa2d0a33434f35142baec7ac"}, - {file = "pyzmq-26.3.0.tar.gz", hash = "sha256:f1cd68b8236faab78138a8fc703f7ca0ad431b17a3fcac696358600d4e6243b3"}, + {file = "pyzmq-27.0.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:b973ee650e8f442ce482c1d99ca7ab537c69098d53a3d046676a484fd710c87a"}, + {file = "pyzmq-27.0.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:661942bc7cd0223d569d808f2e5696d9cc120acc73bf3e88a1f1be7ab648a7e4"}, + {file = "pyzmq-27.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:50360fb2a056ffd16e5f4177eee67f1dd1017332ea53fb095fe7b5bf29c70246"}, + {file = "pyzmq-27.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf209a6dc4b420ed32a7093642843cbf8703ed0a7d86c16c0b98af46762ebefb"}, + {file = "pyzmq-27.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c2dace4a7041cca2fba5357a2d7c97c5effdf52f63a1ef252cfa496875a3762d"}, + {file = "pyzmq-27.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:63af72b2955fc77caf0a77444baa2431fcabb4370219da38e1a9f8d12aaebe28"}, + {file = "pyzmq-27.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e8c4adce8e37e75c4215297d7745551b8dcfa5f728f23ce09bf4e678a9399413"}, + {file = "pyzmq-27.0.0-cp310-cp310-win32.whl", hash = "sha256:5d5ef4718ecab24f785794e0e7536436698b459bfbc19a1650ef55280119d93b"}, + {file = "pyzmq-27.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:e40609380480b3d12c30f841323f42451c755b8fece84235236f5fe5ffca8c1c"}, + {file = "pyzmq-27.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6b0397b0be277b46762956f576e04dc06ced265759e8c2ff41a0ee1aa0064198"}, + {file = "pyzmq-27.0.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:21457825249b2a53834fa969c69713f8b5a79583689387a5e7aed880963ac564"}, + {file = "pyzmq-27.0.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1958947983fef513e6e98eff9cb487b60bf14f588dc0e6bf35fa13751d2c8251"}, + {file = "pyzmq-27.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0dc628b5493f9a8cd9844b8bee9732ef587ab00002157c9329e4fc0ef4d3afa"}, + {file = "pyzmq-27.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7bbe9e1ed2c8d3da736a15694d87c12493e54cc9dc9790796f0321794bbc91f"}, + {file = "pyzmq-27.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc1091f59143b471d19eb64f54bae4f54bcf2a466ffb66fe45d94d8d734eb495"}, + {file = "pyzmq-27.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7011ade88c8e535cf140f8d1a59428676fbbce7c6e54fefce58bf117aefb6667"}, + {file = "pyzmq-27.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2c386339d7e3f064213aede5d03d054b237937fbca6dd2197ac8cf3b25a6b14e"}, + {file = "pyzmq-27.0.0-cp311-cp311-win32.whl", hash = "sha256:0546a720c1f407b2172cb04b6b094a78773491497e3644863cf5c96c42df8cff"}, + {file = "pyzmq-27.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:15f39d50bd6c9091c67315ceb878a4f531957b121d2a05ebd077eb35ddc5efed"}, + {file = "pyzmq-27.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c5817641eebb391a2268c27fecd4162448e03538387093cdbd8bf3510c316b38"}, + {file = "pyzmq-27.0.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:cbabc59dcfaac66655c040dfcb8118f133fb5dde185e5fc152628354c1598e52"}, + {file = "pyzmq-27.0.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:cb0ac5179cba4b2f94f1aa208fbb77b62c4c9bf24dd446278b8b602cf85fcda3"}, + {file = "pyzmq-27.0.0-cp312-abi3-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53a48f0228eab6cbf69fde3aa3c03cbe04e50e623ef92ae395fce47ef8a76152"}, + {file = "pyzmq-27.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:111db5f395e09f7e775f759d598f43cb815fc58e0147623c4816486e1a39dc22"}, + {file = "pyzmq-27.0.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c8878011653dcdc27cc2c57e04ff96f0471e797f5c19ac3d7813a245bcb24371"}, + {file = "pyzmq-27.0.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:c0ed2c1f335ba55b5fdc964622254917d6b782311c50e138863eda409fbb3b6d"}, + {file = "pyzmq-27.0.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e918d70862d4cfd4b1c187310015646a14e1f5917922ab45b29f28f345eeb6be"}, + {file = "pyzmq-27.0.0-cp312-abi3-win32.whl", hash = "sha256:88b4e43cab04c3c0f0d55df3b1eef62df2b629a1a369b5289a58f6fa8b07c4f4"}, + {file = "pyzmq-27.0.0-cp312-abi3-win_amd64.whl", hash = "sha256:dce4199bf5f648a902ce37e7b3afa286f305cd2ef7a8b6ec907470ccb6c8b371"}, + {file = "pyzmq-27.0.0-cp312-abi3-win_arm64.whl", hash = "sha256:56e46bbb85d52c1072b3f809cc1ce77251d560bc036d3a312b96db1afe76db2e"}, + {file = "pyzmq-27.0.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c36ad534c0c29b4afa088dc53543c525b23c0797e01b69fef59b1a9c0e38b688"}, + {file = "pyzmq-27.0.0-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:67855c14173aec36395d7777aaba3cc527b393821f30143fd20b98e1ff31fd38"}, + {file = "pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8617c7d43cd8ccdb62aebe984bfed77ca8f036e6c3e46dd3dddda64b10f0ab7a"}, + {file = "pyzmq-27.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:67bfbcbd0a04c575e8103a6061d03e393d9f80ffdb9beb3189261e9e9bc5d5e9"}, + {file = "pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5cd11d46d7b7e5958121b3eaf4cd8638eff3a720ec527692132f05a57f14341d"}, + {file = "pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:b801c2e40c5aa6072c2f4876de8dccd100af6d9918d4d0d7aa54a1d982fd4f44"}, + {file = "pyzmq-27.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:20d5cb29e8c5f76a127c75b6e7a77e846bc4b655c373baa098c26a61b7ecd0ef"}, + {file = "pyzmq-27.0.0-cp313-cp313t-win32.whl", hash = "sha256:a20528da85c7ac7a19b7384e8c3f8fa707841fd85afc4ed56eda59d93e3d98ad"}, + {file = "pyzmq-27.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d8229f2efece6a660ee211d74d91dbc2a76b95544d46c74c615e491900dc107f"}, + {file = "pyzmq-27.0.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:f4162dbbd9c5c84fb930a36f290b08c93e35fce020d768a16fc8891a2f72bab8"}, + {file = "pyzmq-27.0.0-cp38-cp38-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4e7d0a8d460fba526cc047333bdcbf172a159b8bd6be8c3eb63a416ff9ba1477"}, + {file = "pyzmq-27.0.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:29f44e3c26b9783816ba9ce274110435d8f5b19bbd82f7a6c7612bb1452a3597"}, + {file = "pyzmq-27.0.0-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e435540fa1da54667f0026cf1e8407fe6d8a11f1010b7f06b0b17214ebfcf5e"}, + {file = "pyzmq-27.0.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:51f5726de3532b8222e569990c8aa34664faa97038304644679a51d906e60c6e"}, + {file = "pyzmq-27.0.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:42c7555123679637c99205b1aa9e8f7d90fe29d4c243c719e347d4852545216c"}, + {file = "pyzmq-27.0.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a979b7cf9e33d86c4949df527a3018767e5f53bc3b02adf14d4d8db1db63ccc0"}, + {file = "pyzmq-27.0.0-cp38-cp38-win32.whl", hash = "sha256:26b72c5ae20bf59061c3570db835edb81d1e0706ff141747055591c4b41193f8"}, + {file = "pyzmq-27.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:55a0155b148fe0428285a30922f7213539aa84329a5ad828bca4bbbc665c70a4"}, + {file = "pyzmq-27.0.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:100f6e5052ba42b2533011d34a018a5ace34f8cac67cb03cfa37c8bdae0ca617"}, + {file = "pyzmq-27.0.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:bf6c6b061efd00404b9750e2cfbd9507492c8d4b3721ded76cb03786131be2ed"}, + {file = "pyzmq-27.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee05728c0b0b2484a9fc20466fa776fffb65d95f7317a3419985b8c908563861"}, + {file = "pyzmq-27.0.0-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7cdf07fe0a557b131366f80727ec8ccc4b70d89f1e3f920d94a594d598d754f0"}, + {file = "pyzmq-27.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:90252fa2ff3a104219db1f5ced7032a7b5fc82d7c8d2fec2b9a3e6fd4e25576b"}, + {file = "pyzmq-27.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ea6d441c513bf18c578c73c323acf7b4184507fc244762193aa3a871333c9045"}, + {file = "pyzmq-27.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ae2b34bcfaae20c064948a4113bf8709eee89fd08317eb293ae4ebd69b4d9740"}, + {file = "pyzmq-27.0.0-cp39-cp39-win32.whl", hash = "sha256:5b10bd6f008937705cf6e7bf8b6ece5ca055991e3eb130bca8023e20b86aa9a3"}, + {file = "pyzmq-27.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:00387d12a8af4b24883895f7e6b9495dc20a66027b696536edac35cb988c38f3"}, + {file = "pyzmq-27.0.0-cp39-cp39-win_arm64.whl", hash = "sha256:4c19d39c04c29a6619adfeb19e3735c421b3bfee082f320662f52e59c47202ba"}, + {file = "pyzmq-27.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:656c1866505a5735d0660b7da6d7147174bbf59d4975fc2b7f09f43c9bc25745"}, + {file = "pyzmq-27.0.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:74175b9e12779382432dd1d1f5960ebe7465d36649b98a06c6b26be24d173fab"}, + {file = "pyzmq-27.0.0-pp310-pypy310_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8c6de908465697a8708e4d6843a1e884f567962fc61eb1706856545141d0cbb"}, + {file = "pyzmq-27.0.0-pp310-pypy310_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c644aaacc01d0df5c7072826df45e67301f191c55f68d7b2916d83a9ddc1b551"}, + {file = "pyzmq-27.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:10f70c1d9a446a85013a36871a296007f6fe4232b530aa254baf9da3f8328bc0"}, + {file = "pyzmq-27.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd1dc59763effd1576f8368047c9c31468fce0af89d76b5067641137506792ae"}, + {file = "pyzmq-27.0.0-pp311-pypy311_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:60e8cc82d968174650c1860d7b716366caab9973787a1c060cf8043130f7d0f7"}, + {file = "pyzmq-27.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:14fe7aaac86e4e93ea779a821967360c781d7ac5115b3f1a171ced77065a0174"}, + {file = "pyzmq-27.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6ad0562d4e6abb785be3e4dd68599c41be821b521da38c402bc9ab2a8e7ebc7e"}, + {file = "pyzmq-27.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:9df43a2459cd3a3563404c1456b2c4c69564daa7dbaf15724c09821a3329ce46"}, + {file = "pyzmq-27.0.0-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8c86ea8fe85e2eb0ffa00b53192c401477d5252f6dd1db2e2ed21c1c30d17e5e"}, + {file = "pyzmq-27.0.0-pp38-pypy38_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:c45fee3968834cd291a13da5fac128b696c9592a9493a0f7ce0b47fa03cc574d"}, + {file = "pyzmq-27.0.0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cae73bb6898c4e045fbed5024cb587e4110fddb66f6163bcab5f81f9d4b9c496"}, + {file = "pyzmq-27.0.0-pp38-pypy38_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26d542258c7a1f35a9cff3d887687d3235006134b0ac1c62a6fe1ad3ac10440e"}, + {file = "pyzmq-27.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:04cd50ef3b28e35ced65740fb9956a5b3f77a6ff32fcd887e3210433f437dd0f"}, + {file = "pyzmq-27.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:39ddd3ba0a641f01d8f13a3cfd4c4924eb58e660d8afe87e9061d6e8ca6f7ac3"}, + {file = "pyzmq-27.0.0-pp39-pypy39_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:8ca7e6a0388dd9e1180b14728051068f4efe83e0d2de058b5ff92c63f399a73f"}, + {file = "pyzmq-27.0.0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2524c40891be6a3106885a3935d58452dd83eb7a5742a33cc780a1ad4c49dec0"}, + {file = "pyzmq-27.0.0-pp39-pypy39_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a56e3e5bd2d62a01744fd2f1ce21d760c7c65f030e9522738d75932a14ab62a"}, + {file = "pyzmq-27.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:096af9e133fec3a72108ddefba1e42985cb3639e9de52cfd336b6fc23aa083e9"}, + {file = "pyzmq-27.0.0.tar.gz", hash = "sha256:b1f08eeb9ce1510e6939b6e5dcd46a17765e2333daae78ecf4606808442e52cf"}, ] [package.dependencies] cffi = {version = "*", markers = "implementation_name == \"pypy\""} -[[package]] -name = "questionary" -version = "2.1.0" -description = "Python library to build pretty command line user prompts ⭐️" -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec"}, - {file = "questionary-2.1.0.tar.gz", hash = "sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587"}, -] - -[package.dependencies] -prompt_toolkit = ">=2.0,<4.0" - [[package]] name = "referencing" version = "0.36.2" @@ -5655,19 +5739,19 @@ typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""} [[package]] name = "requests" -version = "2.32.3" +version = "2.32.4" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" @@ -5745,139 +5829,175 @@ typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.1 jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] -name = "rich-click" -version = "1.8.8" -description = "Format click help output nicely with rich" +name = "roman-numerals-py" +version = "3.1.0" +description = "Manipulate well-formed Roman numerals" optional = true -python-versions = ">=3.7" +python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"dev\"" +markers = "python_version >= \"3.11\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "rich_click-1.8.8-py3-none-any.whl", hash = "sha256:205aabd5a98e64ab2c105dee9e368be27480ba004c7dfa2accd0ed44f9f1550e"}, - {file = "rich_click-1.8.8.tar.gz", hash = "sha256:547c618dea916620af05d4a6456da797fbde904c97901f44d2f32f89d85d6c84"}, + {file = "roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c"}, + {file = "roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d"}, ] -[package.dependencies] -click = ">=7" -rich = ">=10.7" -typing_extensions = ">=4" - [package.extras] -dev = ["mypy", "packaging", "pre-commit", "pytest", "pytest-cov", "rich-codex", "ruff", "types-setuptools"] -docs = ["markdown_include", "mkdocs", "mkdocs-glightbox", "mkdocs-material-extensions", "mkdocs-material[imaging] (>=9.5.18,<9.6.0)", "mkdocs-rss-plugin", "mkdocstrings[python]", "rich-codex"] +lint = ["mypy (==1.15.0)", "pyright (==1.1.394)", "ruff (==0.9.7)"] +test = ["pytest (>=8)"] [[package]] name = "rpds-py" -version = "0.23.1" +version = "0.26.0" description = "Python bindings to Rust's persistent data structures (rpds)" optional = true python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "rpds_py-0.23.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2a54027554ce9b129fc3d633c92fa33b30de9f08bc61b32c053dc9b537266fed"}, - {file = "rpds_py-0.23.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b5ef909a37e9738d146519657a1aab4584018746a18f71c692f2f22168ece40c"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ee9d6f0b38efb22ad94c3b68ffebe4c47865cdf4b17f6806d6c674e1feb4246"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7356a6da0562190558c4fcc14f0281db191cdf4cb96e7604c06acfcee96df15"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9441af1d25aed96901f97ad83d5c3e35e6cd21a25ca5e4916c82d7dd0490a4fa"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d8abf7896a91fb97e7977d1aadfcc2c80415d6dc2f1d0fca5b8d0df247248f3"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b08027489ba8fedde72ddd233a5ea411b85a6ed78175f40285bd401bde7466d"}, - {file = "rpds_py-0.23.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fee513135b5a58f3bb6d89e48326cd5aa308e4bcdf2f7d59f67c861ada482bf8"}, - {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:35d5631ce0af26318dba0ae0ac941c534453e42f569011585cb323b7774502a5"}, - {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a20cb698c4a59c534c6701b1c24a968ff2768b18ea2991f886bd8985ce17a89f"}, - {file = "rpds_py-0.23.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e9c206a1abc27e0588cf8b7c8246e51f1a16a103734f7750830a1ccb63f557a"}, - {file = "rpds_py-0.23.1-cp310-cp310-win32.whl", hash = "sha256:d9f75a06ecc68f159d5d7603b734e1ff6daa9497a929150f794013aa9f6e3f12"}, - {file = "rpds_py-0.23.1-cp310-cp310-win_amd64.whl", hash = "sha256:f35eff113ad430b5272bbfc18ba111c66ff525828f24898b4e146eb479a2cdda"}, - {file = "rpds_py-0.23.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b79f5ced71efd70414a9a80bbbfaa7160da307723166f09b69773153bf17c590"}, - {file = "rpds_py-0.23.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c9e799dac1ffbe7b10c1fd42fe4cd51371a549c6e108249bde9cd1200e8f59b4"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721f9c4011b443b6e84505fc00cc7aadc9d1743f1c988e4c89353e19c4a968ee"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f88626e3f5e57432e6191cd0c5d6d6b319b635e70b40be2ffba713053e5147dd"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:285019078537949cecd0190f3690a0b0125ff743d6a53dfeb7a4e6787af154f5"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b92f5654157de1379c509b15acec9d12ecf6e3bc1996571b6cb82a4302060447"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e768267cbe051dd8d1c5305ba690bb153204a09bf2e3de3ae530de955f5b5580"}, - {file = "rpds_py-0.23.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5334a71f7dc1160382d45997e29f2637c02f8a26af41073189d79b95d3321f1"}, - {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d6adb81564af0cd428910f83fa7da46ce9ad47c56c0b22b50872bc4515d91966"}, - {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cafa48f2133d4daa028473ede7d81cd1b9f9e6925e9e4003ebdf77010ee02f35"}, - {file = "rpds_py-0.23.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fced9fd4a07a1ded1bac7e961ddd9753dd5d8b755ba8e05acba54a21f5f1522"}, - {file = "rpds_py-0.23.1-cp311-cp311-win32.whl", hash = "sha256:243241c95174b5fb7204c04595852fe3943cc41f47aa14c3828bc18cd9d3b2d6"}, - {file = "rpds_py-0.23.1-cp311-cp311-win_amd64.whl", hash = "sha256:11dd60b2ffddba85715d8a66bb39b95ddbe389ad2cfcf42c833f1bcde0878eaf"}, - {file = "rpds_py-0.23.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3902df19540e9af4cc0c3ae75974c65d2c156b9257e91f5101a51f99136d834c"}, - {file = "rpds_py-0.23.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:66f8d2a17e5838dd6fb9be6baaba8e75ae2f5fa6b6b755d597184bfcd3cb0eba"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:112b8774b0b4ee22368fec42749b94366bd9b536f8f74c3d4175d4395f5cbd31"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0df046f2266e8586cf09d00588302a32923eb6386ced0ca5c9deade6af9a149"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3288930b947cbebe767f84cf618d2cbe0b13be476e749da0e6a009f986248c"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce473a2351c018b06dd8d30d5da8ab5a0831056cc53b2006e2a8028172c37ce5"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d550d7e9e7d8676b183b37d65b5cd8de13676a738973d330b59dc8312df9c5dc"}, - {file = "rpds_py-0.23.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e14f86b871ea74c3fddc9a40e947d6a5d09def5adc2076ee61fb910a9014fb35"}, - {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1bf5be5ba34e19be579ae873da515a2836a2166d8d7ee43be6ff909eda42b72b"}, - {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7031d493c4465dbc8d40bd6cafefef4bd472b17db0ab94c53e7909ee781b9ef"}, - {file = "rpds_py-0.23.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:55ff4151cfd4bc635e51cfb1c59ac9f7196b256b12e3a57deb9e5742e65941ad"}, - {file = "rpds_py-0.23.1-cp312-cp312-win32.whl", hash = "sha256:a9d3b728f5a5873d84cba997b9d617c6090ca5721caaa691f3b1a78c60adc057"}, - {file = "rpds_py-0.23.1-cp312-cp312-win_amd64.whl", hash = "sha256:b03a8d50b137ee758e4c73638b10747b7c39988eb8e6cd11abb7084266455165"}, - {file = "rpds_py-0.23.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:4caafd1a22e5eaa3732acb7672a497123354bef79a9d7ceed43387d25025e935"}, - {file = "rpds_py-0.23.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:178f8a60fc24511c0eb756af741c476b87b610dba83270fce1e5a430204566a4"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c632419c3870507ca20a37c8f8f5352317aca097639e524ad129f58c125c61c6"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:698a79d295626ee292d1730bc2ef6e70a3ab135b1d79ada8fde3ed0047b65a10"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:271fa2184cf28bdded86bb6217c8e08d3a169fe0bbe9be5e8d96e8476b707122"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b91cceb5add79ee563bd1f70b30896bd63bc5f78a11c1f00a1e931729ca4f1f4"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a6cb95074777f1ecda2ca4fa7717caa9ee6e534f42b7575a8f0d4cb0c24013"}, - {file = "rpds_py-0.23.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:50fb62f8d8364978478b12d5f03bf028c6bc2af04082479299139dc26edf4c64"}, - {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c8f7e90b948dc9dcfff8003f1ea3af08b29c062f681c05fd798e36daa3f7e3e8"}, - {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5b98b6c953e5c2bda51ab4d5b4f172617d462eebc7f4bfdc7c7e6b423f6da957"}, - {file = "rpds_py-0.23.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2893d778d4671ee627bac4037a075168b2673c57186fb1a57e993465dbd79a93"}, - {file = "rpds_py-0.23.1-cp313-cp313-win32.whl", hash = "sha256:2cfa07c346a7ad07019c33fb9a63cf3acb1f5363c33bc73014e20d9fe8b01cdd"}, - {file = "rpds_py-0.23.1-cp313-cp313-win_amd64.whl", hash = "sha256:3aaf141d39f45322e44fc2c742e4b8b4098ead5317e5f884770c8df0c332da70"}, - {file = "rpds_py-0.23.1-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:759462b2d0aa5a04be5b3e37fb8183615f47014ae6b116e17036b131985cb731"}, - {file = "rpds_py-0.23.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3e9212f52074fc9d72cf242a84063787ab8e21e0950d4d6709886fb62bcb91d5"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e9f3a3ac919406bc0414bbbd76c6af99253c507150191ea79fab42fdb35982a"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c04ca91dda8a61584165825907f5c967ca09e9c65fe8966ee753a3f2b019fe1e"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ab923167cfd945abb9b51a407407cf19f5bee35001221f2911dc85ffd35ff4f"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed6f011bedca8585787e5082cce081bac3d30f54520097b2411351b3574e1219"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6959bb9928c5c999aba4a3f5a6799d571ddc2c59ff49917ecf55be2bbb4e3722"}, - {file = "rpds_py-0.23.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1ed7de3c86721b4e83ac440751329ec6a1102229aa18163f84c75b06b525ad7e"}, - {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5fb89edee2fa237584e532fbf78f0ddd1e49a47c7c8cfa153ab4849dc72a35e6"}, - {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7e5413d2e2d86025e73f05510ad23dad5950ab8417b7fc6beaad99be8077138b"}, - {file = "rpds_py-0.23.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d31ed4987d72aabdf521eddfb6a72988703c091cfc0064330b9e5f8d6a042ff5"}, - {file = "rpds_py-0.23.1-cp313-cp313t-win32.whl", hash = "sha256:f3429fb8e15b20961efca8c8b21432623d85db2228cc73fe22756c6637aa39e7"}, - {file = "rpds_py-0.23.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d6f6512a90bd5cd9030a6237f5346f046c6f0e40af98657568fa45695d4de59d"}, - {file = "rpds_py-0.23.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:09cd7dbcb673eb60518231e02874df66ec1296c01a4fcd733875755c02014b19"}, - {file = "rpds_py-0.23.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c6760211eee3a76316cf328f5a8bd695b47b1626d21c8a27fb3b2473a884d597"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72e680c1518733b73c994361e4b06441b92e973ef7d9449feec72e8ee4f713da"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae28144c1daa61366205d32abd8c90372790ff79fc60c1a8ad7fd3c8553a600e"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c698d123ce5d8f2d0cd17f73336615f6a2e3bdcedac07a1291bb4d8e7d82a05a"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98b257ae1e83f81fb947a363a274c4eb66640212516becaff7bef09a5dceacaa"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c9ff044eb07c8468594d12602291c635da292308c8c619244e30698e7fc455a"}, - {file = "rpds_py-0.23.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7938c7b0599a05246d704b3f5e01be91a93b411d0d6cc62275f025293b8a11ce"}, - {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e9cb79ecedfc156c0692257ac7ed415243b6c35dd969baa461a6888fc79f2f07"}, - {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:7b77e07233925bd33fc0022b8537774423e4c6680b6436316c5075e79b6384f4"}, - {file = "rpds_py-0.23.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a970bfaf130c29a679b1d0a6e0f867483cea455ab1535fb427566a475078f27f"}, - {file = "rpds_py-0.23.1-cp39-cp39-win32.whl", hash = "sha256:4233df01a250b3984465faed12ad472f035b7cd5240ea3f7c76b7a7016084495"}, - {file = "rpds_py-0.23.1-cp39-cp39-win_amd64.whl", hash = "sha256:c617d7453a80e29d9973b926983b1e700a9377dbe021faa36041c78537d7b08c"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c1f8afa346ccd59e4e5630d5abb67aba6a9812fddf764fd7eb11f382a345f8cc"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fad784a31869747df4ac968a351e070c06ca377549e4ace94775aaa3ab33ee06"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5a96fcac2f18e5a0a23a75cd27ce2656c66c11c127b0318e508aab436b77428"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e77febf227a1dc3220159355dba68faa13f8dca9335d97504abf428469fb18b"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26bb3e8de93443d55e2e748e9fd87deb5f8075ca7bc0502cfc8be8687d69a2ec"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db7707dde9143a67b8812c7e66aeb2d843fe33cc8e374170f4d2c50bd8f2472d"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1eedaaccc9bb66581d4ae7c50e15856e335e57ef2734dbc5fd8ba3e2a4ab3cb6"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28358c54fffadf0ae893f6c1050e8f8853e45df22483b7fff2f6ab6152f5d8bf"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:633462ef7e61d839171bf206551d5ab42b30b71cac8f10a64a662536e057fdef"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:a98f510d86f689fcb486dc59e6e363af04151e5260ad1bdddb5625c10f1e95f8"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e0397dd0b3955c61ef9b22838144aa4bef6f0796ba5cc8edfc64d468b93798b4"}, - {file = "rpds_py-0.23.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:75307599f0d25bf6937248e5ac4e3bde5ea72ae6618623b86146ccc7845ed00b"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3614d280bf7aab0d3721b5ce0e73434acb90a2c993121b6e81a1c15c665298ac"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e5963ea87f88bddf7edd59644a35a0feecf75f8985430124c253612d4f7d27ae"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad76f44f70aac3a54ceb1813ca630c53415da3a24fd93c570b2dfb4856591017"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c6ae11e6e93728d86aafc51ced98b1658a0080a7dd9417d24bfb955bb09c3c2"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc869af5cba24d45fb0399b0cfdbcefcf6910bf4dee5d74036a57cf5264b3ff4"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c76b32eb2ab650a29e423525e84eb197c45504b1c1e6e17b6cc91fcfeb1a4b1d"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4263320ed887ed843f85beba67f8b2d1483b5947f2dc73a8b068924558bfeace"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f9682a8f71acdf59fd554b82b1c12f517118ee72c0f3944eda461606dfe7eb9"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:754fba3084b70162a6b91efceee8a3f06b19e43dac3f71841662053c0584209a"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:a1c66e71ecfd2a4acf0e4bd75e7a3605afa8f9b28a3b497e4ba962719df2be57"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8d67beb6002441faef8251c45e24994de32c4c8686f7356a1f601ad7c466f7c3"}, - {file = "rpds_py-0.23.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a1e17d8dc8e57d8e0fd21f8f0f0a5211b3fa258b2e444c2053471ef93fe25a00"}, - {file = "rpds_py-0.23.1.tar.gz", hash = "sha256:7f3240dcfa14d198dba24b8b9cb3b108c06b68d45b7babd9eefc1038fdf7e707"}, + {file = "rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37"}, + {file = "rpds_py-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:777c62479d12395bfb932944e61e915741e364c843afc3196b694db3d669fcd0"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec671691e72dff75817386aa02d81e708b5a7ec0dec6669ec05213ff6b77e1bd"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a1cb5d6ce81379401bbb7f6dbe3d56de537fb8235979843f0d53bc2e9815a79"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f789e32fa1fb6a7bf890e0124e7b42d1e60d28ebff57fe806719abb75f0e9a3"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c55b0a669976cf258afd718de3d9ad1b7d1fe0a91cd1ab36f38b03d4d4aeaaf"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70d9ec912802ecfd6cd390dadb34a9578b04f9bcb8e863d0a7598ba5e9e7ccc"}, + {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3021933c2cb7def39d927b9862292e0f4c75a13d7de70eb0ab06efed4c508c19"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a7898b6ca3b7d6659e55cdac825a2e58c638cbf335cde41f4619e290dd0ad11"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:12bff2ad9447188377f1b2794772f91fe68bb4bbfa5a39d7941fbebdbf8c500f"}, + {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:191aa858f7d4902e975d4cf2f2d9243816c91e9605070aeb09c0a800d187e323"}, + {file = "rpds_py-0.26.0-cp310-cp310-win32.whl", hash = "sha256:b37a04d9f52cb76b6b78f35109b513f6519efb481d8ca4c321f6a3b9580b3f45"}, + {file = "rpds_py-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:38721d4c9edd3eb6670437d8d5e2070063f305bfa2d5aa4278c51cedcd508a84"}, + {file = "rpds_py-0.26.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e8cb77286025bdb21be2941d64ac6ca016130bfdcd228739e8ab137eb4406ed"}, + {file = "rpds_py-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e09330b21d98adc8ccb2dbb9fc6cb434e8908d4c119aeaa772cb1caab5440a0"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9c1b92b774b2e68d11193dc39620d62fd8ab33f0a3c77ecdabe19c179cdbc1"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:824e6d3503ab990d7090768e4dfd9e840837bae057f212ff9f4f05ec6d1975e7"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ad7fd2258228bf288f2331f0a6148ad0186b2e3643055ed0db30990e59817a6"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dc23bbb3e06ec1ea72d515fb572c1fea59695aefbffb106501138762e1e915e"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80bf832ac7b1920ee29a426cdca335f96a2b5caa839811803e999b41ba9030d"}, + {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0919f38f5542c0a87e7b4afcafab6fd2c15386632d249e9a087498571250abe3"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d422b945683e409000c888e384546dbab9009bb92f7c0b456e217988cf316107"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a7711fa562ba2da1aa757e11024ad6d93bad6ad7ede5afb9af144623e5f76a"}, + {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238e8c8610cb7c29460e37184f6799547f7e09e6a9bdbdab4e8edb90986a2318"}, + {file = "rpds_py-0.26.0-cp311-cp311-win32.whl", hash = "sha256:893b022bfbdf26d7bedb083efeea624e8550ca6eb98bf7fea30211ce95b9201a"}, + {file = "rpds_py-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:87a5531de9f71aceb8af041d72fc4cab4943648d91875ed56d2e629bef6d4c03"}, + {file = "rpds_py-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:de2713f48c1ad57f89ac25b3cb7daed2156d8e822cf0eca9b96a6f990718cc41"}, + {file = "rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d"}, + {file = "rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a"}, + {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3"}, + {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2"}, + {file = "rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44"}, + {file = "rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c"}, + {file = "rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8"}, + {file = "rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d"}, + {file = "rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04"}, + {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9"}, + {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba"}, + {file = "rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b"}, + {file = "rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5"}, + {file = "rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256"}, + {file = "rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618"}, + {file = "rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f"}, + {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c"}, + {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0"}, + {file = "rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9"}, + {file = "rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9"}, + {file = "rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a"}, + {file = "rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246"}, + {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33"}, + {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953"}, + {file = "rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9"}, + {file = "rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37"}, + {file = "rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867"}, + {file = "rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da"}, + {file = "rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8"}, + {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170"}, + {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e"}, + {file = "rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f"}, + {file = "rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7"}, + {file = "rpds_py-0.26.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7a48af25d9b3c15684059d0d1fc0bc30e8eee5ca521030e2bffddcab5be40226"}, + {file = "rpds_py-0.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c71c2f6bf36e61ee5c47b2b9b5d47e4d1baad6426bfed9eea3e858fc6ee8806"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d815d48b1804ed7867b539236b6dd62997850ca1c91cad187f2ddb1b7bbef19"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84cfbd4d4d2cdeb2be61a057a258d26b22877266dd905809e94172dff01a42ae"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbaa70553ca116c77717f513e08815aec458e6b69a028d4028d403b3bc84ff37"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39bfea47c375f379d8e87ab4bb9eb2c836e4f2069f0f65731d85e55d74666387"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1533b7eb683fb5f38c1d68a3c78f5fdd8f1412fa6b9bf03b40f450785a0ab915"}, + {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ab0ee51f560d179b057555b4f601b7df909ed31312d301b99f8b9fc6028284"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e5162afc9e0d1f9cae3b577d9c29ddbab3505ab39012cb794d94a005825bde21"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:43f10b007033f359bc3fa9cd5e6c1e76723f056ffa9a6b5c117cc35720a80292"}, + {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3730a48e5622e598293eee0762b09cff34dd3f271530f47b0894891281f051d"}, + {file = "rpds_py-0.26.0-cp39-cp39-win32.whl", hash = "sha256:4b1f66eb81eab2e0ff5775a3a312e5e2e16bf758f7b06be82fb0d04078c7ac51"}, + {file = "rpds_py-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:519067e29f67b5c90e64fb1a6b6e9d2ec0ba28705c51956637bac23a2f4ddae1"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3c0909c5234543ada2515c05dc08595b08d621ba919629e94427e8e03539c958"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c1fb0cda2abcc0ac62f64e2ea4b4e64c57dfd6b885e693095460c61bde7bb18e"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d142d2d6cf9b31c12aa4878d82ed3b2324226270b89b676ac62ccd7df52d08"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a547e21c5610b7e9093d870be50682a6a6cf180d6da0f42c47c306073bfdbbf6"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35e9a70a0f335371275cdcd08bc5b8051ac494dd58bff3bbfb421038220dc871"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dfa6115c6def37905344d56fb54c03afc49104e2ca473d5dedec0f6606913b4"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313cfcd6af1a55a286a3c9a25f64af6d0e46cf60bc5798f1db152d97a216ff6f"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7bf2496fa563c046d05e4d232d7b7fd61346e2402052064b773e5c378bf6f73"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa81873e2c8c5aa616ab8e017a481a96742fdf9313c40f14338ca7dbf50cb55f"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:68ffcf982715f5b5b7686bdd349ff75d422e8f22551000c24b30eaa1b7f7ae84"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6188de70e190847bb6db3dc3981cbadff87d27d6fe9b4f0e18726d55795cee9b"}, + {file = "rpds_py-0.26.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1c962145c7473723df9722ba4c058de12eb5ebedcb4e27e7d902920aa3831ee8"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f61a9326f80ca59214d1cceb0a09bb2ece5b2563d4e0cd37bfd5515c28510674"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:183f857a53bcf4b1b42ef0f57ca553ab56bdd170e49d8091e96c51c3d69ca696"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:941c1cfdf4799d623cf3aa1d326a6b4fdb7a5799ee2687f3516738216d2262fb"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72a8d9564a717ee291f554eeb4bfeafe2309d5ec0aa6c475170bdab0f9ee8e88"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:511d15193cbe013619dd05414c35a7dedf2088fcee93c6bbb7c77859765bd4e8"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1f9741b603a8d8fedb0ed5502c2bc0accbc51f43e2ad1337fe7259c2b77a5"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4019a9d473c708cf2f16415688ef0b4639e07abaa569d72f74745bbeffafa2c7"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:093d63b4b0f52d98ebae33b8c50900d3d67e0666094b1be7a12fffd7f65de74b"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2abe21d8ba64cded53a2a677e149ceb76dcf44284202d737178afe7ba540c1eb"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:4feb7511c29f8442cbbc28149a92093d32e815a28aa2c50d333826ad2a20fdf0"}, + {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a90a13408a7a856b87be8a9f008fff53c5080eea4e4180f6c2e546e4a972fb5d"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ac51b65e8dc76cf4949419c54c5528adb24fc721df722fd452e5fbc236f5c40"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b2093224a18c6508d95cfdeba8db9cbfd6f3494e94793b58972933fcee4c6d"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f01a5d6444a3258b00dc07b6ea4733e26f8072b788bef750baa37b370266137"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6e2c12160c72aeda9d1283e612f68804621f448145a210f1bf1d79151c47090"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb28c1f569f8d33b2b5dcd05d0e6ef7005d8639c54c2f0be824f05aedf715255"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1766b5724c3f779317d5321664a343c07773c8c5fd1532e4039e6cc7d1a815be"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b6d9e5a2ed9c4988c8f9b28b3bc0e3e5b1aaa10c28d210a594ff3a8c02742daf"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b5f7a446ddaf6ca0fad9a5535b56fbfc29998bf0e0b450d174bbec0d600e1d72"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:eed5ac260dd545fbc20da5f4f15e7efe36a55e0e7cf706e4ec005b491a9546a0"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:582462833ba7cee52e968b0341b85e392ae53d44c0f9af6a5927c80e539a8b67"}, + {file = "rpds_py-0.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69a607203441e07e9a8a529cff1d5b73f6a160f22db1097211e6212a68567d11"}, + {file = "rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0"}, ] [[package]] @@ -5903,43 +6023,43 @@ files = [ [[package]] name = "ruff" -version = "0.5.5" +version = "0.11.11" description = "An extremely fast Python linter and code formatter, written in Rust." optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\" or extra == \"ruff\"" files = [ - {file = "ruff-0.5.5-py3-none-linux_armv6l.whl", hash = "sha256:605d589ec35d1da9213a9d4d7e7a9c761d90bba78fc8790d1c5e65026c1b9eaf"}, - {file = "ruff-0.5.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00817603822a3e42b80f7c3298c8269e09f889ee94640cd1fc7f9329788d7bf8"}, - {file = "ruff-0.5.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:187a60f555e9f865a2ff2c6984b9afeffa7158ba6e1eab56cb830404c942b0f3"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe26fc46fa8c6e0ae3f47ddccfbb136253c831c3289bba044befe68f467bfb16"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4ad25dd9c5faac95c8e9efb13e15803cd8bbf7f4600645a60ffe17c73f60779b"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f70737c157d7edf749bcb952d13854e8f745cec695a01bdc6e29c29c288fc36e"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:cfd7de17cef6ab559e9f5ab859f0d3296393bc78f69030967ca4d87a541b97a0"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a09b43e02f76ac0145f86a08e045e2ea452066f7ba064fd6b0cdccb486f7c3e7"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0b856cb19c60cd40198be5d8d4b556228e3dcd545b4f423d1ad812bfdca5884"}, - {file = "ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091"}, - {file = "ruff-0.5.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ac9dc814e510436e30d0ba535f435a7f3dc97f895f844f5b3f347ec8c228a523"}, - {file = "ruff-0.5.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:af9bdf6c389b5add40d89b201425b531e0a5cceb3cfdcc69f04d3d531c6be74f"}, - {file = "ruff-0.5.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d40a8533ed545390ef8315b8e25c4bb85739b90bd0f3fe1280a29ae364cc55d8"}, - {file = "ruff-0.5.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:cab904683bf9e2ecbbe9ff235bfe056f0eba754d0168ad5407832928d579e7ab"}, - {file = "ruff-0.5.5-py3-none-win32.whl", hash = "sha256:696f18463b47a94575db635ebb4c178188645636f05e934fdf361b74edf1bb2d"}, - {file = "ruff-0.5.5-py3-none-win_amd64.whl", hash = "sha256:50f36d77f52d4c9c2f1361ccbfbd09099a1b2ea5d2b2222c586ab08885cf3445"}, - {file = "ruff-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3191317d967af701f1b73a31ed5788795936e423b7acce82a2b63e26eb3e89d6"}, - {file = "ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a"}, + {file = "ruff-0.11.11-py3-none-linux_armv6l.whl", hash = "sha256:9924e5ae54125ed8958a4f7de320dab7380f6e9fa3195e3dc3b137c6842a0092"}, + {file = "ruff-0.11.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8a93276393d91e952f790148eb226658dd275cddfde96c6ca304873f11d2ae4"}, + {file = "ruff-0.11.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d6e333dbe2e6ae84cdedefa943dfd6434753ad321764fd937eef9d6b62022bcd"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7885d9a5e4c77b24e8c88aba8c80be9255fa22ab326019dac2356cff42089fc6"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b5ab797fcc09121ed82e9b12b6f27e34859e4227080a42d090881be888755d4"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e231ff3132c1119ece836487a02785f099a43992b95c2f62847d29bace3c75ac"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a97c9babe1d4081037a90289986925726b802d180cca784ac8da2bbbc335f709"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8c4ddcbe8a19f59f57fd814b8b117d4fcea9bee7c0492e6cf5fdc22cfa563c8"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6224076c344a7694c6fbbb70d4f2a7b730f6d47d2a9dc1e7f9d9bb583faf390b"}, + {file = "ruff-0.11.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:882821fcdf7ae8db7a951df1903d9cb032bbe838852e5fc3c2b6c3ab54e39875"}, + {file = "ruff-0.11.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:dcec2d50756463d9df075a26a85a6affbc1b0148873da3997286caf1ce03cae1"}, + {file = "ruff-0.11.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99c28505ecbaeb6594701a74e395b187ee083ee26478c1a795d35084d53ebd81"}, + {file = "ruff-0.11.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9263f9e5aa4ff1dec765e99810f1cc53f0c868c5329b69f13845f699fe74f639"}, + {file = "ruff-0.11.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:64ac6f885e3ecb2fdbb71de2701d4e34526651f1e8503af8fb30d4915a3fe345"}, + {file = "ruff-0.11.11-py3-none-win32.whl", hash = "sha256:1adcb9a18802268aaa891ffb67b1c94cd70578f126637118e8099b8e4adcf112"}, + {file = "ruff-0.11.11-py3-none-win_amd64.whl", hash = "sha256:748b4bb245f11e91a04a4ff0f96e386711df0a30412b9fe0c74d5bdc0e4a531f"}, + {file = "ruff-0.11.11-py3-none-win_arm64.whl", hash = "sha256:6c51f136c0364ab1b774767aa8b86331bd8e9d414e2d107db7a2189f35ea1f7b"}, + {file = "ruff-0.11.11.tar.gz", hash = "sha256:7774173cc7c1980e6bf67569ebb7085989a78a103922fb83ef3dfe230cd0687d"}, ] [[package]] name = "s3transfer" -version = "0.11.4" +version = "0.13.0" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "s3transfer-0.11.4-py3-none-any.whl", hash = "sha256:ac265fa68318763a03bf2dc4f39d5cbd6a9e178d81cc9483ad27da33637e320d"}, - {file = "s3transfer-0.11.4.tar.gz", hash = "sha256:559f161658e1cf0a911f45940552c696735f5c74e64362e515f333ebed87d679"}, + {file = "s3transfer-0.13.0-py3-none-any.whl", hash = "sha256:0148ef34d6dd964d0d8cf4311b2b21c474693e57c2e069ec708ce043d2b527be"}, + {file = "s3transfer-0.13.0.tar.gz", hash = "sha256:f5e6db74eb7776a37208001113ea7aa97695368242b364d73e91c981ac522177"}, ] [package.dependencies] @@ -5988,7 +6108,7 @@ description = "A set of python modules for machine learning and data mining" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"dev\" or extra == \"design\"" +markers = "python_version < \"3.10\" and (extra == \"dev\" or extra == \"design\")" files = [ {file = "scikit_learn-1.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d056391530ccd1e501056160e3c9673b4da4805eb67eb2bdf4e983e1f9c9204e"}, {file = "scikit_learn-1.6.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0c8d036eb937dbb568c6242fa598d551d88fb4399c0344d95c001980ec1c7d36"}, @@ -6037,17 +6157,68 @@ install = ["joblib (>=1.2.0)", "numpy (>=1.19.5)", "scipy (>=1.6.0)", "threadpoo maintenance = ["conda-lock (==2.5.6)"] tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc (>=1.2.0)", "pandas (>=1.1.5)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.0.0)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.5.1)", "scikit-image (>=0.17.2)"] +[[package]] +name = "scikit-learn" +version = "1.7.0" +description = "A set of python modules for machine learning and data mining" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\" and (extra == \"dev\" or extra == \"design\")" +files = [ + {file = "scikit_learn-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9fe7f51435f49d97bd41d724bb3e11eeb939882af9c29c931a8002c357e8cdd5"}, + {file = "scikit_learn-1.7.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d0c93294e1e1acbee2d029b1f2a064f26bd928b284938d51d412c22e0c977eb3"}, + {file = "scikit_learn-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf3755f25f145186ad8c403312f74fb90df82a4dfa1af19dc96ef35f57237a94"}, + {file = "scikit_learn-1.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2726c8787933add436fb66fb63ad18e8ef342dfb39bbbd19dc1e83e8f828a85a"}, + {file = "scikit_learn-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:e2539bb58886a531b6e86a510c0348afaadd25005604ad35966a85c2ec378800"}, + {file = "scikit_learn-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ef09b1615e1ad04dc0d0054ad50634514818a8eb3ee3dee99af3bffc0ef5007"}, + {file = "scikit_learn-1.7.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:7d7240c7b19edf6ed93403f43b0fcb0fe95b53bc0b17821f8fb88edab97085ef"}, + {file = "scikit_learn-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80bd3bd4e95381efc47073a720d4cbab485fc483966f1709f1fd559afac57ab8"}, + {file = "scikit_learn-1.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dbe48d69aa38ecfc5a6cda6c5df5abef0c0ebdb2468e92437e2053f84abb8bc"}, + {file = "scikit_learn-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:8fa979313b2ffdfa049ed07252dc94038def3ecd49ea2a814db5401c07f1ecfa"}, + {file = "scikit_learn-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c2c7243d34aaede0efca7a5a96d67fddaebb4ad7e14a70991b9abee9dc5c0379"}, + {file = "scikit_learn-1.7.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:9f39f6a811bf3f15177b66c82cbe0d7b1ebad9f190737dcdef77cfca1ea3c19c"}, + {file = "scikit_learn-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63017a5f9a74963d24aac7590287149a8d0f1a0799bbe7173c0d8ba1523293c0"}, + {file = "scikit_learn-1.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b2f8a0b1e73e9a08b7cc498bb2aeab36cdc1f571f8ab2b35c6e5d1c7115d97d"}, + {file = "scikit_learn-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:34cc8d9d010d29fb2b7cbcd5ccc24ffdd80515f65fe9f1e4894ace36b267ce19"}, + {file = "scikit_learn-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5b7974f1f32bc586c90145df51130e02267e4b7e77cab76165c76cf43faca0d9"}, + {file = "scikit_learn-1.7.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:014e07a23fe02e65f9392898143c542a50b6001dbe89cb867e19688e468d049b"}, + {file = "scikit_learn-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7e7ced20582d3a5516fb6f405fd1d254e1f5ce712bfef2589f51326af6346e8"}, + {file = "scikit_learn-1.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1babf2511e6ffd695da7a983b4e4d6de45dce39577b26b721610711081850906"}, + {file = "scikit_learn-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:5abd2acff939d5bd4701283f009b01496832d50ddafa83c90125a4e41c33e314"}, + {file = "scikit_learn-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e39d95a929b112047c25b775035c8c234c5ca67e681ce60d12413afb501129f7"}, + {file = "scikit_learn-1.7.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:0521cb460426c56fee7e07f9365b0f45ec8ca7b2d696534ac98bfb85e7ae4775"}, + {file = "scikit_learn-1.7.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:317ca9f83acbde2883bd6bb27116a741bfcb371369706b4f9973cf30e9a03b0d"}, + {file = "scikit_learn-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:126c09740a6f016e815ab985b21e3a0656835414521c81fc1a8da78b679bdb75"}, + {file = "scikit_learn-1.7.0.tar.gz", hash = "sha256:c01e869b15aec88e2cdb73d27f15bdbe03bce8e2fb43afbe77c45d399e73a5a3"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.22.0" +scipy = ">=1.8.0" +threadpoolctl = ">=3.1.0" + +[package.extras] +benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.16.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] +docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==3.0.1)"] +tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] + [[package]] name = "scikit-rf" -version = "1.6.2" +version = "1.8.0" description = "Object Oriented Microwave Engineering" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"scikit-rf\"" files = [ - {file = "scikit_rf-1.6.2-py3-none-any.whl", hash = "sha256:7c4144197318bbd23c070cf7759d238d36311312fe7d4942cbd074e228cbec10"}, - {file = "scikit_rf-1.6.2.tar.gz", hash = "sha256:31650a4c200aed0af2f8808e35510d15705b5722d507737fccec6e7695c3db03"}, + {file = "scikit_rf-1.8.0-py3-none-any.whl", hash = "sha256:81a4a7d6b9197f20c46949e7a8c17f3e214967074578e92751c023d873aae030"}, + {file = "scikit_rf-1.8.0.tar.gz", hash = "sha256:fcf54b90e37792680c09f02d4f0768b17cfb7cb783e16d0210f98e27d1ff30a8"}, ] [package.dependencies] @@ -6111,59 +6282,59 @@ test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "po [[package]] name = "scipy" -version = "1.15.2" +version = "1.15.3" description = "Fundamental algorithms for scientific computing in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version >= \"3.10\"" -files = [ - {file = "scipy-1.15.2-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a2ec871edaa863e8213ea5df811cd600734f6400b4af272e1c011e69401218e9"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:6f223753c6ea76983af380787611ae1291e3ceb23917393079dcc746ba60cfb5"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:ecf797d2d798cf7c838c6d98321061eb3e72a74710e6c40540f0e8087e3b499e"}, - {file = "scipy-1.15.2-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:9b18aa747da280664642997e65aab1dd19d0c3d17068a04b3fe34e2559196cb9"}, - {file = "scipy-1.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87994da02e73549dfecaed9e09a4f9d58a045a053865679aeb8d6d43747d4df3"}, - {file = "scipy-1.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69ea6e56d00977f355c0f84eba69877b6df084516c602d93a33812aa04d90a3d"}, - {file = "scipy-1.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:888307125ea0c4466287191e5606a2c910963405ce9671448ff9c81c53f85f58"}, - {file = "scipy-1.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9412f5e408b397ff5641080ed1e798623dbe1ec0d78e72c9eca8992976fa65aa"}, - {file = "scipy-1.15.2-cp310-cp310-win_amd64.whl", hash = "sha256:b5e025e903b4f166ea03b109bb241355b9c42c279ea694d8864d033727205e65"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:92233b2df6938147be6fa8824b8136f29a18f016ecde986666be5f4d686a91a4"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:62ca1ff3eb513e09ed17a5736929429189adf16d2d740f44e53270cc800ecff1"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4c6676490ad76d1c2894d77f976144b41bd1a4052107902238047fb6a473e971"}, - {file = "scipy-1.15.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8bf5cb4a25046ac61d38f8d3c3426ec11ebc350246a4642f2f315fe95bda655"}, - {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a8e34cf4c188b6dd004654f88586d78f95639e48a25dfae9c5e34a6dc34547e"}, - {file = "scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28a0d2c2075946346e4408b211240764759e0fabaeb08d871639b5f3b1aca8a0"}, - {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:42dabaaa798e987c425ed76062794e93a243be8f0f20fff6e7a89f4d61cb3d40"}, - {file = "scipy-1.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6f5e296ec63c5da6ba6fa0343ea73fd51b8b3e1a300b0a8cae3ed4b1122c7462"}, - {file = "scipy-1.15.2-cp311-cp311-win_amd64.whl", hash = "sha256:597a0c7008b21c035831c39927406c6181bcf8f60a73f36219b69d010aa04737"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c4697a10da8f8765bb7c83e24a470da5797e37041edfd77fd95ba3811a47c4fd"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:869269b767d5ee7ea6991ed7e22b3ca1f22de73ab9a49c44bad338b725603301"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bad78d580270a4d32470563ea86c6590b465cb98f83d760ff5b0990cb5518a93"}, - {file = "scipy-1.15.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b09ae80010f52efddb15551025f9016c910296cf70adbf03ce2a8704f3a5ad20"}, - {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a6fd6eac1ce74a9f77a7fc724080d507c5812d61e72bd5e4c489b042455865e"}, - {file = "scipy-1.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b871df1fe1a3ba85d90e22742b93584f8d2b8e6124f8372ab15c71b73e428b8"}, - {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:03205d57a28e18dfd39f0377d5002725bf1f19a46f444108c29bdb246b6c8a11"}, - {file = "scipy-1.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:601881dfb761311045b03114c5fe718a12634e5608c3b403737ae463c9885d53"}, - {file = "scipy-1.15.2-cp312-cp312-win_amd64.whl", hash = "sha256:e7c68b6a43259ba0aab737237876e5c2c549a031ddb7abc28c7b47f22e202ded"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01edfac9f0798ad6b46d9c4c9ca0e0ad23dbf0b1eb70e96adb9fa7f525eff0bf"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:08b57a9336b8e79b305a143c3655cc5bdbe6d5ece3378578888d2afbb51c4e37"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:54c462098484e7466362a9f1672d20888f724911a74c22ae35b61f9c5919183d"}, - {file = "scipy-1.15.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:cf72ff559a53a6a6d77bd8eefd12a17995ffa44ad86c77a5df96f533d4e6c6bb"}, - {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9de9d1416b3d9e7df9923ab23cd2fe714244af10b763975bea9e4f2e81cebd27"}, - {file = "scipy-1.15.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb530e4794fc8ea76a4a21ccb67dea33e5e0e60f07fc38a49e821e1eae3b71a0"}, - {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5ea7ed46d437fc52350b028b1d44e002646e28f3e8ddc714011aaf87330f2f32"}, - {file = "scipy-1.15.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:11e7ad32cf184b74380f43d3c0a706f49358b904fa7d5345f16ddf993609184d"}, - {file = "scipy-1.15.2-cp313-cp313-win_amd64.whl", hash = "sha256:a5080a79dfb9b78b768cebf3c9dcbc7b665c5875793569f48bf0e2b1d7f68f6f"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:447ce30cee6a9d5d1379087c9e474628dab3db4a67484be1b7dc3196bfb2fac9"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:c90ebe8aaa4397eaefa8455a8182b164a6cc1d59ad53f79943f266d99f68687f"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:def751dd08243934c884a3221156d63e15234a3155cf25978b0a668409d45eb6"}, - {file = "scipy-1.15.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:302093e7dfb120e55515936cb55618ee0b895f8bcaf18ff81eca086c17bd80af"}, - {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd5b77413e1855351cdde594eca99c1f4a588c2d63711388b6a1f1c01f62274"}, - {file = "scipy-1.15.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d0194c37037707b2afa7a2f2a924cf7bac3dc292d51b6a925e5fcb89bc5c776"}, - {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:bae43364d600fdc3ac327db99659dcb79e6e7ecd279a75fe1266669d9a652828"}, - {file = "scipy-1.15.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f031846580d9acccd0044efd1a90e6f4df3a6e12b4b6bd694a7bc03a89892b28"}, - {file = "scipy-1.15.2-cp313-cp313t-win_amd64.whl", hash = "sha256:fe8a9eb875d430d81755472c5ba75e84acc980e4a8f6204d402849234d3017db"}, - {file = "scipy-1.15.2.tar.gz", hash = "sha256:cd58a314d92838f7e6f755c8a2167ead4f27e1fd5c1251fd54289569ef3495ec"}, +markers = "python_version == \"3.10\"" +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, ] [package.dependencies] @@ -6171,9 +6342,65 @@ numpy = ">=1.23.5,<2.5" [package.extras] dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] -doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.16.5)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +[[package]] +name = "scipy" +version = "1.16.0" +description = "Fundamental algorithms for scientific computing in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "scipy-1.16.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:deec06d831b8f6b5fb0b652433be6a09db29e996368ce5911faf673e78d20085"}, + {file = "scipy-1.16.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d30c0fe579bb901c61ab4bb7f3eeb7281f0d4c4a7b52dbf563c89da4fd2949be"}, + {file = "scipy-1.16.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:b2243561b45257f7391d0f49972fca90d46b79b8dbcb9b2cb0f9df928d370ad4"}, + {file = "scipy-1.16.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:e6d7dfc148135e9712d87c5f7e4f2ddc1304d1582cb3a7d698bbadedb61c7afd"}, + {file = "scipy-1.16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90452f6a9f3fe5a2cf3748e7be14f9cc7d9b124dce19667b54f5b429d680d539"}, + {file = "scipy-1.16.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a2f0bf2f58031c8701a8b601df41701d2a7be17c7ffac0a4816aeba89c4cdac8"}, + {file = "scipy-1.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c4abb4c11fc0b857474241b812ce69ffa6464b4bd8f4ecb786cf240367a36a7"}, + {file = "scipy-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b370f8f6ac6ef99815b0d5c9f02e7ade77b33007d74802efc8316c8db98fd11e"}, + {file = "scipy-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:a16ba90847249bedce8aa404a83fb8334b825ec4a8e742ce6012a7a5e639f95c"}, + {file = "scipy-1.16.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:7eb6bd33cef4afb9fa5f1fb25df8feeb1e52d94f21a44f1d17805b41b1da3180"}, + {file = "scipy-1.16.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1dbc8fdba23e4d80394ddfab7a56808e3e6489176d559c6c71935b11a2d59db1"}, + {file = "scipy-1.16.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:7dcf42c380e1e3737b343dec21095c9a9ad3f9cbe06f9c05830b44b1786c9e90"}, + {file = "scipy-1.16.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26ec28675f4a9d41587266084c626b02899db373717d9312fa96ab17ca1ae94d"}, + {file = "scipy-1.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:952358b7e58bd3197cfbd2f2f2ba829f258404bdf5db59514b515a8fe7a36c52"}, + {file = "scipy-1.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03931b4e870c6fef5b5c0970d52c9f6ddd8c8d3e934a98f09308377eba6f3824"}, + {file = "scipy-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:512c4f4f85912767c351a0306824ccca6fd91307a9f4318efe8fdbd9d30562ef"}, + {file = "scipy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e69f798847e9add03d512eaf5081a9a5c9a98757d12e52e6186ed9681247a1ac"}, + {file = "scipy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:adf9b1999323ba335adc5d1dc7add4781cb5a4b0ef1e98b79768c05c796c4e49"}, + {file = "scipy-1.16.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:e9f414cbe9ca289a73e0cc92e33a6a791469b6619c240aa32ee18abdce8ab451"}, + {file = "scipy-1.16.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:bbba55fb97ba3cdef9b1ee973f06b09d518c0c7c66a009c729c7d1592be1935e"}, + {file = "scipy-1.16.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:58e0d4354eacb6004e7aa1cd350e5514bd0270acaa8d5b36c0627bb3bb486974"}, + {file = "scipy-1.16.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:75b2094ec975c80efc273567436e16bb794660509c12c6a31eb5c195cbf4b6dc"}, + {file = "scipy-1.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b65d232157a380fdd11a560e7e21cde34fdb69d65c09cb87f6cc024ee376351"}, + {file = "scipy-1.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d8747f7736accd39289943f7fe53a8333be7f15a82eea08e4afe47d79568c32"}, + {file = "scipy-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb9f147a1b8529bb7fec2a85cf4cf42bdfadf9e83535c309a11fdae598c88e8b"}, + {file = "scipy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d2b83c37edbfa837a8923d19c749c1935ad3d41cf196006a24ed44dba2ec4358"}, + {file = "scipy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe"}, + {file = "scipy-1.16.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:f91b87e1689f0370690e8470916fe1b2308e5b2061317ff76977c8f836452a47"}, + {file = "scipy-1.16.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:88a6ca658fb94640079e7a50b2ad3b67e33ef0f40e70bdb7dc22017dae73ac08"}, + {file = "scipy-1.16.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ae902626972f1bd7e4e86f58fd72322d7f4ec7b0cfc17b15d4b7006efc385176"}, + {file = "scipy-1.16.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:8cb824c1fc75ef29893bc32b3ddd7b11cf9ab13c1127fe26413a05953b8c32ed"}, + {file = "scipy-1.16.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:de2db7250ff6514366a9709c2cba35cb6d08498e961cba20d7cff98a7ee88938"}, + {file = "scipy-1.16.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e85800274edf4db8dd2e4e93034f92d1b05c9421220e7ded9988b16976f849c1"}, + {file = "scipy-1.16.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f720300a3024c237ace1cb11f9a84c38beb19616ba7c4cdcd771047a10a1706"}, + {file = "scipy-1.16.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aad603e9339ddb676409b104c48a027e9916ce0d2838830691f39552b38a352e"}, + {file = "scipy-1.16.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f56296fefca67ba605fd74d12f7bd23636267731a72cb3947963e76b8c0a25db"}, + {file = "scipy-1.16.0.tar.gz", hash = "sha256:b5ef54021e832869c8cfb03bc3bf20366cbcd426e02a58e8a58d7584dfbb8f62"}, +] + +[package.dependencies] +numpy = ">=1.25.2,<2.6" + +[package.extras] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + [[package]] name = "send2trash" version = "1.8.3" @@ -6194,15 +6421,15 @@ win32 = ["pywin32 ; sys_platform == \"win32\""] [[package]] name = "setuptools" -version = "77.0.3" +version = "80.9.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"dev\" or extra == \"docs\" or python_version >= \"3.12\"" +markers = "python_version >= \"3.12\" or (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") and platform_system == \"Linux\" and sys_platform == \"darwin\" and platform_machine == \"x86_64\" or (extra == \"dev\" or extra == \"pytorch\" or extra == \"docs\") and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "setuptools-77.0.3-py3-none-any.whl", hash = "sha256:67122e78221da5cf550ddd04cf8742c8fe12094483749a792d56cd669d6cf58c"}, - {file = "setuptools-77.0.3.tar.gz", hash = "sha256:583b361c8da8de57403743e756609670de6fb2345920e36dc5c2d914c319c945"}, + {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, + {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, ] [package.extras] @@ -6221,6 +6448,7 @@ description = "Manipulation and analysis of geometric objects" optional = false python-versions = ">=3.7" groups = ["main"] +markers = "python_version < \"3.10\"" files = [ {file = "shapely-2.0.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:33fb10e50b16113714ae40adccf7670379e9ccf5b7a41d0002046ba2b8f0f691"}, {file = "shapely-2.0.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f44eda8bd7a4bccb0f281264b34bf3518d8c4c9a8ffe69a1a05dabf6e8461147"}, @@ -6273,24 +6501,83 @@ numpy = ">=1.14,<3" docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] test = ["pytest", "pytest-cov"] +[[package]] +name = "shapely" +version = "2.1.1" +description = "Manipulation and analysis of geometric objects" +optional = false +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "shapely-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d8ccc872a632acb7bdcb69e5e78df27213f7efd195882668ffba5405497337c6"}, + {file = "shapely-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f24f2ecda1e6c091da64bcbef8dd121380948074875bd1b247b3d17e99407099"}, + {file = "shapely-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45112a5be0b745b49e50f8829ce490eb67fefb0cea8d4f8ac5764bfedaa83d2d"}, + {file = "shapely-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c10ce6f11904d65e9bbb3e41e774903c944e20b3f0b282559885302f52f224a"}, + {file = "shapely-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:61168010dfe4e45f956ffbbaf080c88afce199ea81eb1f0ac43230065df320bd"}, + {file = "shapely-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cacf067cdff741cd5c56a21c52f54ece4e4dad9d311130493a791997da4a886b"}, + {file = "shapely-2.1.1-cp310-cp310-win32.whl", hash = "sha256:23b8772c3b815e7790fb2eab75a0b3951f435bc0fce7bb146cb064f17d35ab4f"}, + {file = "shapely-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:2c7b2b6143abf4fa77851cef8ef690e03feade9a0d48acd6dc41d9e0e78d7ca6"}, + {file = "shapely-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:587a1aa72bc858fab9b8c20427b5f6027b7cbc92743b8e2c73b9de55aa71c7a7"}, + {file = "shapely-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fa5c53b0791a4b998f9ad84aad456c988600757a96b0a05e14bba10cebaaaea"}, + {file = "shapely-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aabecd038841ab5310d23495253f01c2a82a3aedae5ab9ca489be214aa458aa7"}, + {file = "shapely-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586f6aee1edec04e16227517a866df3e9a2e43c1f635efc32978bb3dc9c63753"}, + {file = "shapely-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b9878b9e37ad26c72aada8de0c9cfe418d9e2ff36992a1693b7f65a075b28647"}, + {file = "shapely-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d9a531c48f289ba355e37b134e98e28c557ff13965d4653a5228d0f42a09aed0"}, + {file = "shapely-2.1.1-cp311-cp311-win32.whl", hash = "sha256:4866de2673a971820c75c0167b1f1cd8fb76f2d641101c23d3ca021ad0449bab"}, + {file = "shapely-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:20a9d79958b3d6c70d8a886b250047ea32ff40489d7abb47d01498c704557a93"}, + {file = "shapely-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2827365b58bf98efb60affc94a8e01c56dd1995a80aabe4b701465d86dcbba43"}, + {file = "shapely-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9c551f7fa7f1e917af2347fe983f21f212863f1d04f08eece01e9c275903fad"}, + {file = "shapely-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78dec4d4fbe7b1db8dc36de3031767e7ece5911fb7782bc9e95c5cdec58fb1e9"}, + {file = "shapely-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:872d3c0a7b8b37da0e23d80496ec5973c4692920b90de9f502b5beb994bbaaef"}, + {file = "shapely-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2e2b9125ebfbc28ecf5353511de62f75a8515ae9470521c9a693e4bb9fbe0cf1"}, + {file = "shapely-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4b96cea171b3d7f6786976a0520f178c42792897653ecca0c5422fb1e6946e6d"}, + {file = "shapely-2.1.1-cp312-cp312-win32.whl", hash = "sha256:39dca52201e02996df02e447f729da97cfb6ff41a03cb50f5547f19d02905af8"}, + {file = "shapely-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:13d643256f81d55a50013eff6321142781cf777eb6a9e207c2c9e6315ba6044a"}, + {file = "shapely-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3004a644d9e89e26c20286d5fdc10f41b1744c48ce910bd1867fdff963fe6c48"}, + {file = "shapely-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1415146fa12d80a47d13cfad5310b3c8b9c2aa8c14a0c845c9d3d75e77cb54f6"}, + {file = "shapely-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21fcab88b7520820ec16d09d6bea68652ca13993c84dffc6129dc3607c95594c"}, + {file = "shapely-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5ce6a5cc52c974b291237a96c08c5592e50f066871704fb5b12be2639d9026a"}, + {file = "shapely-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:04e4c12a45a1d70aeb266618d8cf81a2de9c4df511b63e105b90bfdfb52146de"}, + {file = "shapely-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6ca74d851ca5264aae16c2b47e96735579686cb69fa93c4078070a0ec845b8d8"}, + {file = "shapely-2.1.1-cp313-cp313-win32.whl", hash = "sha256:fd9130501bf42ffb7e0695b9ea17a27ae8ce68d50b56b6941c7f9b3d3453bc52"}, + {file = "shapely-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:ab8d878687b438a2f4c138ed1a80941c6ab0029e0f4c785ecfe114413b498a97"}, + {file = "shapely-2.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0c062384316a47f776305ed2fa22182717508ffdeb4a56d0ff4087a77b2a0f6d"}, + {file = "shapely-2.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4ecf6c196b896e8f1360cc219ed4eee1c1e5f5883e505d449f263bd053fb8c05"}, + {file = "shapely-2.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb00070b4c4860f6743c600285109c273cca5241e970ad56bb87bef0be1ea3a0"}, + {file = "shapely-2.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d14a9afa5fa980fbe7bf63706fdfb8ff588f638f145a1d9dbc18374b5b7de913"}, + {file = "shapely-2.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b640e390dabde790e3fb947198b466e63223e0a9ccd787da5f07bcb14756c28d"}, + {file = "shapely-2.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:69e08bf9697c1b73ec6aa70437db922bafcea7baca131c90c26d59491a9760f9"}, + {file = "shapely-2.1.1-cp313-cp313t-win32.whl", hash = "sha256:ef2d09d5a964cc90c2c18b03566cf918a61c248596998a0301d5b632beadb9db"}, + {file = "shapely-2.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:8cb8f17c377260452e9d7720eeaf59082c5f8ea48cf104524d953e5d36d4bdb7"}, + {file = "shapely-2.1.1.tar.gz", hash = "sha256:500621967f2ffe9642454808009044c21e5b35db89ce69f8a2042c2ffd0e2772"}, +] + +[package.dependencies] +numpy = ">=1.21" + +[package.extras] +docs = ["matplotlib", "numpydoc (==1.1.*)", "sphinx", "sphinx-book-theme", "sphinx-remove-toctrees"] +test = ["pytest", "pytest-cov", "scipy-doctest"] + [[package]] name = "signac" -version = "2.2.0" +version = "2.3.0" description = "Manage large and heterogeneous data spaces on the file system." optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "signac-2.2.0-py3-none-any.whl", hash = "sha256:a1681a6da40d7eb898612da0492ef2dead3a66adaae8f9ddae9a96020184369e"}, - {file = "signac-2.2.0.tar.gz", hash = "sha256:145dcf98e125db16a71a3dc1ced81c96094cbc347c690d77da9ce73a13319010"}, + {file = "signac-2.3.0-py3-none-any.whl", hash = "sha256:a4985f77323fe116bbdd28bb39354a908b598bd1551500ea2bff7ca81aca06c0"}, + {file = "signac-2.3.0.tar.gz", hash = "sha256:0cd73bf31b29f7a6954e3ea9ce5e4904193d53650f2029064467e69ebfe76c9e"}, ] [package.dependencies] filelock = ">=3.0" packaging = ">=15.0" -synced-collections = ">=1.0.0" -tqdm = ">=4.10.0" +synced_collections = ">=1.0.0" +tqdm = ">=4.46.1" [package.extras] h5 = ["h5py"] @@ -6456,28 +6743,28 @@ files = [ [[package]] name = "snowballstemmer" -version = "2.2.0" -description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +version = "3.0.1" +description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." optional = true -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, - {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, + {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, + {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, ] [[package]] name = "soupsieve" -version = "2.6" +version = "2.7" description = "A modern CSS selector implementation for Beautiful Soup." optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, - {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, + {file = "soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4"}, + {file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"}, ] [[package]] @@ -6525,7 +6812,7 @@ description = "Python documentation generator" optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version >= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" +markers = "python_version == \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, @@ -6555,6 +6842,43 @@ docs = ["sphinxcontrib-websupport"] lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] +[[package]] +name = "sphinx" +version = "8.2.3" +description = "Python documentation generator" +optional = true +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\" and (extra == \"dev\" or extra == \"docs\")" +files = [ + {file = "sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3"}, + {file = "sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348"}, +] + +[package.dependencies] +alabaster = ">=0.7.14" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" +imagesize = ">=1.3" +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +roman-numerals-py = ">=1.0.0" +snowballstemmer = ">=2.2" +sphinxcontrib-applehelp = ">=1.0.7" +sphinxcontrib-devhelp = ">=1.0.6" +sphinxcontrib-htmlhelp = ">=2.0.6" +sphinxcontrib-jsmath = ">=1.0.1" +sphinxcontrib-qthelp = ">=1.0.6" +sphinxcontrib-serializinghtml = ">=1.1.9" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["betterproto (==2.0.0b6)", "mypy (==1.15.0)", "pypi-attestations (==0.0.21)", "pyright (==1.1.395)", "pytest (>=8.0)", "ruff (==0.9.9)", "sphinx-lint (>=0.9)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.19.0.20250219)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241128)", "types-requests (==2.32.0.20241016)", "types-urllib3 (==1.26.25.14)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "pytest-xdist[psutil] (>=3.4)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] + [[package]] name = "sphinx-book-theme" version = "1.1.4" @@ -6645,6 +6969,22 @@ dev = ["nox", "pre-commit"] doc = ["pydata-sphinx-theme", "sphinx (<6)", "sphinx-copybutton", "sphinx-design"] test = ["beautifulsoup4", "pytest", "pytest-cov"] +[[package]] +name = "sphinx-last-updated-by-git" +version = "0.3.8" +description = "Get the \"last updated\" time for each Sphinx page from Git" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"dev\" or extra == \"docs\"" +files = [ + {file = "sphinx_last_updated_by_git-0.3.8-py3-none-any.whl", hash = "sha256:6382c8285ac1f222483a58569b78c0371af5e55f7fbf9c01e5e8a72d6fdfa499"}, + {file = "sphinx_last_updated_by_git-0.3.8.tar.gz", hash = "sha256:c145011f4609d841805b69a9300099fc02fed8f5bb9e5bcef77d97aea97b7761"}, +] + +[package.dependencies] +sphinx = ">=1.8" + [[package]] name = "sphinx-notfound-page" version = "1.1.0" @@ -6667,22 +7007,22 @@ test = ["tox"] [[package]] name = "sphinx-sitemap" -version = "2.6.0" +version = "2.7.2" description = "Sitemap generator for Sphinx" optional = true python-versions = "*" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "sphinx_sitemap-2.6.0-py3-none-any.whl", hash = "sha256:7478e417d141f99c9af27ccd635f44c03a471a08b20e778a0f9daef7ace1d30b"}, - {file = "sphinx_sitemap-2.6.0.tar.gz", hash = "sha256:5e0c66b9f2e371ede80c659866a9eaad337d46ab02802f9c7e5f7bc5893c28d2"}, + {file = "sphinx_sitemap-2.7.2-py3-none-any.whl", hash = "sha256:1a6a8dcecb0ffb85fd37678f785cfcc40adfe3eebafb05e678971e5260b117e4"}, + {file = "sphinx_sitemap-2.7.2.tar.gz", hash = "sha256:819e028e27579b47efa0e2f863b87136b711c45f13e84730610e80316f6883da"}, ] [package.dependencies] -sphinx = ">=1.2" +sphinx-last-updated-by-git = "*" [package.extras] -dev = ["build", "flake8", "pre-commit", "pytest", "sphinx", "tox"] +dev = ["build", "flake8", "pre-commit", "pytest", "sphinx", "sphinx-last-updated-by-git", "tox"] [[package]] name = "sphinx-tabs" @@ -6851,15 +7191,15 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] [[package]] name = "sympy" -version = "1.13.1" +version = "1.14.0" description = "Computer algebra system (CAS) in Python" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"pytorch\"" files = [ - {file = "sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8"}, - {file = "sympy-1.13.1.tar.gz", hash = "sha256:9cebf7e04ff162015ce31c9c6c9144daa34a93bd082f54fd8f12deca4f47515f"}, + {file = "sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5"}, + {file = "sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517"}, ] [package.dependencies] @@ -6924,38 +7264,38 @@ numpy = ">=1.22.0" [[package]] name = "tensorstore" -version = "0.1.72" +version = "0.1.76" description = "Read and write large, multi-dimensional arrays" optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "tensorstore-0.1.72-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:a41b4fe0603943d23472619a8ada70b8d2c9458747fad88b0ce7b29f1ccf4e74"}, - {file = "tensorstore-0.1.72-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:170172b698fefb4b5507c6cb339ca0b75d56d12ba6a43d9569c61800c1eeb121"}, - {file = "tensorstore-0.1.72-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b71134b85f540e17a1ae65da1fb906781b7470ef0ed71d98d29459325897f574"}, - {file = "tensorstore-0.1.72-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08c5318535aac5e20e247c6e9b43f5887b2293f548de7279650bc73804ccf3ed"}, - {file = "tensorstore-0.1.72-cp310-cp310-win_amd64.whl", hash = "sha256:9113d3fcf78c1366688aa90ee7efdc86b57962ea72276944cc57e916a6180749"}, - {file = "tensorstore-0.1.72-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:599cc7b26b0c96373e89ff5bcf9b76e832802169229680bef985b10011f9bae7"}, - {file = "tensorstore-0.1.72-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a7e7b02da26ca5c95b3c613efd0fe10c082dfa4dc3e9818fefc69e30fe70ea1e"}, - {file = "tensorstore-0.1.72-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a6825cdb6751663ca0bd9abd528ea354ad2199f549bf1f36feac79a6c06efe2"}, - {file = "tensorstore-0.1.72-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed916b9aeca242a3f367679f65ba376149251ebb28b873becd76c73b688399b6"}, - {file = "tensorstore-0.1.72-cp311-cp311-win_amd64.whl", hash = "sha256:5d410c879dc4b34036ec38e20ff05c7e3b0ad5d1eb595412b27a9dbb5e435035"}, - {file = "tensorstore-0.1.72-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:92fac5e2cbc90e5ca8fc72c5bf112816d981e266a3cf9fb1681ba8b3f59537ef"}, - {file = "tensorstore-0.1.72-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c9413f8318a4fa259ec5325f569c0759bccee936df44bd2f7bb35c8afdcdfc8"}, - {file = "tensorstore-0.1.72-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c0f722218f494b1631dbec451b9863f579054e27da2f39aab418db4493694abe"}, - {file = "tensorstore-0.1.72-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5dced3f367308e9fa8e7b72e9e57a4c491fa47c066e035ac33421e2b2408e3f"}, - {file = "tensorstore-0.1.72-cp312-cp312-win_amd64.whl", hash = "sha256:721d599db0113d75ab6ba1365989bbaf2ab752d7a6268f975c8bfd3a8eb6084b"}, - {file = "tensorstore-0.1.72-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:9c3a36f681ffcc104ba931d471447e8901e64e8cc6913b61792870ff59529961"}, - {file = "tensorstore-0.1.72-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0cd951e593a17babbbde1410cfadb4a04e1cddfa5ace0de5ccb41029223f96b9"}, - {file = "tensorstore-0.1.72-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fdfa0118be0721c110bcbe7e464758f78d3e14ee8c30a911eb8f4465e6c2e81"}, - {file = "tensorstore-0.1.72-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed6fe937b0433b573c3d6805d0759d33ccc24aa2aba720e4b8ba689c2f9775f"}, - {file = "tensorstore-0.1.72-cp313-cp313-win_amd64.whl", hash = "sha256:66c0658689243af0825fff222fb56fdf05a8553bcb3b471dbf18830161302986"}, - {file = "tensorstore-0.1.72.tar.gz", hash = "sha256:763d7f6898711783f199c8226a9c0b259546f5c6d9b4dc0ad3c9e39627060022"}, -] - -[package.dependencies] -ml_dtypes = ">=0.3.1" + {file = "tensorstore-0.1.76-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:97e9eeab539369b99828c07e1d7da93062da91b65503dafe06d941208b0869d3"}, + {file = "tensorstore-0.1.76-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a9c6f207a0b5f5138f7844307e5cb96587a73e9ba7b5edb6429524cca985e2c3"}, + {file = "tensorstore-0.1.76-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05aae734cfaf5c1356b6f2c56226526607361c6e9aa6751df395dda53c3783b1"}, + {file = "tensorstore-0.1.76-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7574f837d8bfccf374795100be23f155eff3040f8b0f2010b1a0b2e1d4d6f791"}, + {file = "tensorstore-0.1.76-cp310-cp310-win_amd64.whl", hash = "sha256:9c964c7538805867894f6ba4a03dfa57e434b73d0c563d93fcbf6245eb67cc2c"}, + {file = "tensorstore-0.1.76-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1c882dcf30049952cb6b183c70bd1922815cdbceca8d4115a7fbeb3b5513f9e4"}, + {file = "tensorstore-0.1.76-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:262b856b21626688cefd11913737a94800b1ba3061d56d70babc439ef69587bc"}, + {file = "tensorstore-0.1.76-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf1c7fb71cd07bfdf37ae4f297c0a6895b011562f4050f5c8f52f5753cc24cc"}, + {file = "tensorstore-0.1.76-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b24f21bbd4830822422e984bc023a37ce7db08be02138c01c96870e62d041e7f"}, + {file = "tensorstore-0.1.76-cp311-cp311-win_amd64.whl", hash = "sha256:36ba59d99d8279802793405fb8615803ea0e136ad439e6fe0ab3c3d7df22179d"}, + {file = "tensorstore-0.1.76-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:b68450983ccad9e7774e81b2fa37daef1b72c774fd939d9eb4065d6aa70e666a"}, + {file = "tensorstore-0.1.76-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b7a3856f884279e40f90bad87d0da70869879e124835e650c6b16c80f64fbc4"}, + {file = "tensorstore-0.1.76-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8709a98ae0b453eb23525c07372c2be1f6bbd978bba53319f26a1f2a83a77c2a"}, + {file = "tensorstore-0.1.76-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:267edea8f1596f2bd67017ff97b7b350bf3f95ff84947a8babadc5e17ca53663"}, + {file = "tensorstore-0.1.76-cp312-cp312-win_amd64.whl", hash = "sha256:f66ac63d0c63c3336ac4dc61f1f97b6afe8b512e586ddfdbc91f19175787f321"}, + {file = "tensorstore-0.1.76-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:a471994b156daa3cadb0e4968e29202fa2e8c7ddcd28d825499bb5637caa0983"}, + {file = "tensorstore-0.1.76-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:98175dc64935b49467cb7664a431b9a06e9df9b5cab94f9a1fdb24a30b2d69d3"}, + {file = "tensorstore-0.1.76-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9e30577f1197ea3573102912482dced95e4c6ff72087ffeb99b5d8b496bf81a"}, + {file = "tensorstore-0.1.76-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20782f833bfa3c59dd3787f657388054c54ee0ab48dad181b360e3e5e81e4c4b"}, + {file = "tensorstore-0.1.76-cp313-cp313-win_amd64.whl", hash = "sha256:e84fc11b36fcd55cfd1c5dfc60de9d54d7d95c3de074f4d854914067e82a6740"}, + {file = "tensorstore-0.1.76.tar.gz", hash = "sha256:ed0d565e7a038a84b1b5b5d9f7397caec200b53941d8889f44b7f63dd6abffe7"}, +] + +[package.dependencies] +ml_dtypes = ">=0.5.0" numpy = ">=1.22.0" [[package]] @@ -7084,15 +7424,15 @@ files = [ [[package]] name = "tomlkit" -version = "0.13.2" +version = "0.13.3" description = "Style preserving TOML library" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, - {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, + {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, + {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, ] [[package]] @@ -7109,33 +7449,37 @@ files = [ [[package]] name = "torch" -version = "2.6.0" +version = "2.7.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.9.0" groups = ["main"] markers = "sys_platform == \"darwin\" and (extra == \"dev\" or extra == \"pytorch\")" files = [ - {file = "torch-2.6.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:6860df13d9911ac158f4c44031609700e1eba07916fff62e21e6ffa0a9e01961"}, - {file = "torch-2.6.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c4f103a49830ce4c7561ef4434cc7926e5a5fe4e5eb100c19ab36ea1e2b634ab"}, - {file = "torch-2.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:56eeaf2ecac90da5d9e35f7f35eb286da82673ec3c582e310a8d1631a1c02341"}, - {file = "torch-2.6.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:09e06f9949e1a0518c5b09fe95295bc9661f219d9ecb6f9893e5123e10696628"}, - {file = "torch-2.6.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:7979834102cd5b7a43cc64e87f2f3b14bd0e1458f06e9f88ffa386d07c7446e1"}, - {file = "torch-2.6.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:ccbd0320411fe1a3b3fec7b4d3185aa7d0c52adac94480ab024b5c8f74a0bf1d"}, - {file = "torch-2.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:46763dcb051180ce1ed23d1891d9b1598e07d051ce4c9d14307029809c4d64f7"}, - {file = "torch-2.6.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:94fc63b3b4bedd327af588696559f68c264440e2503cc9e6954019473d74ae21"}, - {file = "torch-2.6.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:2bb8987f3bb1ef2675897034402373ddfc8f5ef0e156e2d8cfc47cacafdda4a9"}, - {file = "torch-2.6.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:b789069020c5588c70d5c2158ac0aa23fd24a028f34a8b4fcb8fcb4d7efcf5fb"}, - {file = "torch-2.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:7e1448426d0ba3620408218b50aa6ada88aeae34f7a239ba5431f6c8774b1239"}, - {file = "torch-2.6.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:9a610afe216a85a8b9bc9f8365ed561535c93e804c2a317ef7fabcc5deda0989"}, - {file = "torch-2.6.0-cp313-cp313-manylinux1_x86_64.whl", hash = "sha256:4874a73507a300a5d089ceaff616a569e7bb7c613c56f37f63ec3ffac65259cf"}, - {file = "torch-2.6.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:a0d5e1b9874c1a6c25556840ab8920569a7a4137afa8a63a32cee0bc7d89bd4b"}, - {file = "torch-2.6.0-cp313-cp313-win_amd64.whl", hash = "sha256:510c73251bee9ba02ae1cb6c9d4ee0907b3ce6020e62784e2d7598e0cfa4d6cc"}, - {file = "torch-2.6.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:ff96f4038f8af9f7ec4231710ed4549da1bdebad95923953a25045dcf6fd87e2"}, - {file = "torch-2.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:9ea955317cfcd3852b1402b62af258ce735c2edeee42ca9419b6bc889e5ae053"}, - {file = "torch-2.6.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:bb2c6c3e65049f081940f5ab15c9136c7de40d3f01192541c920a07c7c585b7e"}, - {file = "torch-2.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:683410f97984103148e31b38a8631acf31c3034c020c0f4d26171e7626d8317a"}, - {file = "torch-2.6.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:265f70de5fd45b864d924b64be1797f86e76c8e48a02c2a3a6fc7ec247d2226c"}, + {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a103b5d782af5bd119b81dbcc7ffc6fa09904c423ff8db397a1e6ea8fd71508f"}, + {file = "torch-2.7.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:fe955951bdf32d182ee8ead6c3186ad54781492bf03d547d31771a01b3d6fb7d"}, + {file = "torch-2.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:885453d6fba67d9991132143bf7fa06b79b24352f4506fd4d10b309f53454162"}, + {file = "torch-2.7.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:d72acfdb86cee2a32c0ce0101606f3758f0d8bb5f8f31e7920dc2809e963aa7c"}, + {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:236f501f2e383f1cb861337bdf057712182f910f10aeaf509065d54d339e49b2"}, + {file = "torch-2.7.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:06eea61f859436622e78dd0cdd51dbc8f8c6d76917a9cf0555a333f9eac31ec1"}, + {file = "torch-2.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:8273145a2e0a3c6f9fd2ac36762d6ee89c26d430e612b95a99885df083b04e52"}, + {file = "torch-2.7.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:aea4fc1bf433d12843eb2c6b2204861f43d8364597697074c8d38ae2507f8730"}, + {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:27ea1e518df4c9de73af7e8a720770f3628e7f667280bce2be7a16292697e3fa"}, + {file = "torch-2.7.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c33360cfc2edd976c2633b3b66c769bdcbbf0e0b6550606d188431c81e7dd1fc"}, + {file = "torch-2.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:d8bf6e1856ddd1807e79dc57e54d3335f2b62e6f316ed13ed3ecfe1fc1df3d8b"}, + {file = "torch-2.7.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:787687087412c4bd68d315e39bc1223f08aae1d16a9e9771d95eabbb04ae98fb"}, + {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:03563603d931e70722dce0e11999d53aa80a375a3d78e6b39b9f6805ea0a8d28"}, + {file = "torch-2.7.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:d632f5417b6980f61404a125b999ca6ebd0b8b4bbdbb5fbbba44374ab619a412"}, + {file = "torch-2.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:23660443e13995ee93e3d844786701ea4ca69f337027b05182f5ba053ce43b38"}, + {file = "torch-2.7.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:0da4f4dba9f65d0d203794e619fe7ca3247a55ffdcbd17ae8fb83c8b2dc9b585"}, + {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:e08d7e6f21a617fe38eeb46dd2213ded43f27c072e9165dc27300c9ef9570934"}, + {file = "torch-2.7.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:30207f672328a42df4f2174b8f426f354b2baa0b7cca3a0adb3d6ab5daf00dc8"}, + {file = "torch-2.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:79042feca1c634aaf6603fe6feea8c6b30dfa140a6bbc0b973e2260c7e79a22e"}, + {file = "torch-2.7.1-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:988b0cbc4333618a1056d2ebad9eb10089637b659eb645434d0809d8d937b946"}, + {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:e0d81e9a12764b6f3879a866607c8ae93113cbcad57ce01ebde63eb48a576369"}, + {file = "torch-2.7.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:8394833c44484547ed4a47162318337b88c97acdb3273d85ea06e03ffff44998"}, + {file = "torch-2.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:df41989d9300e6e3c19ec9f56f856187a6ef060c3662fe54f4b6baf1fc90bd19"}, + {file = "torch-2.7.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:a737b5edd1c44a5c1ece2e9f3d00df9d1b3fb9541138bee56d83d38293fb6c9d"}, ] [package.dependencies] @@ -7143,22 +7487,23 @@ filelock = "*" fsspec = "*" jinja2 = "*" networkx = "*" -nvidia-cublas-cu12 = {version = "12.4.5.8", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu12 = {version = "9.1.0.70", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu12 = {version = "11.2.1.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu12 = {version = "10.3.5.147", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu12 = {version = "11.6.1.9", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu12 = {version = "12.3.1.170", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparselt-cu12 = {version = "0.6.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu12 = {version = "2.21.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvjitlink-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu12 = {version = "12.4.127", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cublas-cu12 = {version = "12.6.4.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.6.80", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "9.5.1.17", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.3.0.4", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufile-cu12 = {version = "1.11.1.6", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.7.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.7.1.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.5.4.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparselt-cu12 = {version = "0.6.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.26.2", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvjitlink-cu12 = {version = "12.6.85", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.6.77", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} setuptools = {version = "*", markers = "python_version >= \"3.12\""} -sympy = {version = "1.13.1", markers = "python_version >= \"3.9\""} -triton = {version = "3.2.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +sympy = ">=1.13.3" +triton = {version = "3.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} typing-extensions = ">=4.10.0" [package.extras] @@ -7167,30 +7512,31 @@ optree = ["optree (>=0.13.0)"] [[package]] name = "torch" -version = "2.6.0+cpu" +version = "2.7.1+cpu" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.9.0" groups = ["main"] markers = "sys_platform != \"darwin\" and (extra == \"dev\" or extra == \"pytorch\")" files = [ - {file = "torch-2.6.0+cpu-cp310-cp310-linux_x86_64.whl", hash = "sha256:35a9e78b7e4096968b54c1a198687b981569c50ae93e661aa430f9fd208da102"}, - {file = "torch-2.6.0+cpu-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:90832f4d118c566b8652a2196ac695fc1f14cf420db27b5a1b41c7eaaf2141e9"}, - {file = "torch-2.6.0+cpu-cp310-cp310-win_amd64.whl", hash = "sha256:6e22f0b13db8d53e55bcb3b46c9dd4b6676d1c44051b56753e745cec3075b333"}, - {file = "torch-2.6.0+cpu-cp311-cp311-linux_x86_64.whl", hash = "sha256:5b6ae523bfb67088a17ca7734d131548a2e60346c622621e4248ed09dd0790cc"}, - {file = "torch-2.6.0+cpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:d3dab9fb0294f268aec28e8aaba834e9d006b90a50db5bc2fe2191a9d48c6084"}, - {file = "torch-2.6.0+cpu-cp311-cp311-win_amd64.whl", hash = "sha256:24c9d3d13b9ea769dd7bd5c11cfa1fc463fd7391397156565484565ca685d908"}, - {file = "torch-2.6.0+cpu-cp312-cp312-linux_x86_64.whl", hash = "sha256:59e78aa0c690f70734e42670036d6b541930b8eabbaa18d94e090abf14cc4d91"}, - {file = "torch-2.6.0+cpu-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:318290e8924353c61b125cdc8768d15208704e279e7757c113b9620740deca98"}, - {file = "torch-2.6.0+cpu-cp312-cp312-win_amd64.whl", hash = "sha256:4027d982eb2781c93825ab9527f17fbbb12dbabf422298e4b954be60016f87d8"}, - {file = "torch-2.6.0+cpu-cp313-cp313-linux_x86_64.whl", hash = "sha256:e70ee2e37ad27a90201d101a41c2e10df7cf15a9ebd17c084f54cf2518c57bdf"}, - {file = "torch-2.6.0+cpu-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:b5e7e8d561b263b5ad8049736281cd12c78e51e7bc1a913fd4098fd0e0b96347"}, - {file = "torch-2.6.0+cpu-cp313-cp313-win_amd64.whl", hash = "sha256:b436a6c62d086dc5b32f5721b59f0ca8ad3bf9de09ee9b5b83dbf1e7a7e22c60"}, - {file = "torch-2.6.0+cpu-cp313-cp313t-linux_x86_64.whl", hash = "sha256:fb34d6cc4e6e20e66d74852c3d84e0301dc5e1a7c822076ef288886f978390f0"}, - {file = "torch-2.6.0+cpu-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7cac05af909ee1c5c2915e8f3efaa1ea015e7e414be0ff53071402b9e4f3c7df"}, - {file = "torch-2.6.0+cpu-cp39-cp39-linux_x86_64.whl", hash = "sha256:b68274aeb4047ba8c73e903f0621e2a4adb54ad5282b0845689c3e1dcd2e2546"}, - {file = "torch-2.6.0+cpu-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:2ab9c6b3d6eea506bda9b82a0155e974d8ef8e38b417589d144568b4fa59afe1"}, - {file = "torch-2.6.0+cpu-cp39-cp39-win_amd64.whl", hash = "sha256:e4a85b58ed455915ee66809ca45e0190a76d652d7e6210b72f53a0219459613b"}, + {file = "torch-2.7.1+cpu-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:c0df17cee97653d09a4e84488a33d21217f9b24208583c55cf28f0045aab0766"}, + {file = "torch-2.7.1+cpu-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1f04a373a3f643821f721da9898ef77dce73b5b6bfc64486f0976f7fb5f90e83"}, + {file = "torch-2.7.1+cpu-cp310-cp310-win_amd64.whl", hash = "sha256:b4cc706973655151f198d027ed34c92ab31a3db55676b44251194e1280631426"}, + {file = "torch-2.7.1+cpu-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5fe6045b8f426bf2d0426e4fe009f1667a954ec2aeb82f1bd0bf60c6d7a85445"}, + {file = "torch-2.7.1+cpu-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a1684793e352f03fa14f78857e55d65de4ada8405ded1da2bf4f452179c4b779"}, + {file = "torch-2.7.1+cpu-cp311-cp311-win_amd64.whl", hash = "sha256:7b977eccbc85ae2bd19d6998de7b1f1f4bd3c04eaffd3015deb7934389783399"}, + {file = "torch-2.7.1+cpu-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3bf2db5adf77b433844f080887ade049c4705ddf9fe1a32023ff84ff735aa5ad"}, + {file = "torch-2.7.1+cpu-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:8f8b3cfc53010a4b4a3c7ecb88c212e9decc4f5eeb6af75c3c803937d2d60947"}, + {file = "torch-2.7.1+cpu-cp312-cp312-win_amd64.whl", hash = "sha256:0bc887068772233f532b51a3e8c8cfc682ae62bef74bf4e0c53526c8b9e4138f"}, + {file = "torch-2.7.1+cpu-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:eb17646792ac4374ffc87e42369f45d21eff17c790868963b90483ef0b6db4ef"}, + {file = "torch-2.7.1+cpu-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:84ea1f6a1d15663037d01b121d6e33bb9da3c90af8e069e5072c30f413455a57"}, + {file = "torch-2.7.1+cpu-cp313-cp313-win_amd64.whl", hash = "sha256:b66f77f6f67317344ee083aa7ac4751a14395fcb38060d564bf513978d267153"}, + {file = "torch-2.7.1+cpu-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:56136a2aca6707df3c8811e46ea2d379eaafd18e656e2fd51e8e4d0ca995651b"}, + {file = "torch-2.7.1+cpu-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:355614185a2aea7155f9c88a20bfd49de5f3063866f3cf9b2f21b6e9e59e31e0"}, + {file = "torch-2.7.1+cpu-cp313-cp313t-win_amd64.whl", hash = "sha256:464bca1bc9452f2ccd676514688896e66b9488f2a0268ecd3ac497cf09c5aac1"}, + {file = "torch-2.7.1+cpu-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:a4551cb97b83df5f93fc0d7538332535828581e1db2f179afc287027afbdd6e8"}, + {file = "torch-2.7.1+cpu-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:d205cac087d60bc176bdc0b63a1d00dc7a4ee5ac76fd20a2ca318ac65674167e"}, + {file = "torch-2.7.1+cpu-cp39-cp39-win_amd64.whl", hash = "sha256:d25435bdc4780d3cb512aad55142aca9584ae1fe8f8691cda6d32f19faf5d58e"}, ] [package.dependencies] @@ -7199,7 +7545,7 @@ fsspec = "*" jinja2 = "*" networkx = "*" setuptools = {version = "*", markers = "python_version >= \"3.12\""} -sympy = {version = "1.13.1", markers = "python_version >= \"3.9\""} +sympy = ">=1.13.3" typing-extensions = ">=4.10.0" [package.extras] @@ -7213,37 +7559,38 @@ reference = "torch-cpu" [[package]] name = "tornado" -version = "6.4.2" +version = "6.5.1" description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, - {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, - {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"}, - {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"}, - {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"}, - {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"}, - {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"}, - {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"}, - {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"}, - {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"}, - {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"}, + {file = "tornado-6.5.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d50065ba7fd11d3bd41bcad0825227cc9a95154bad83239357094c36708001f7"}, + {file = "tornado-6.5.1-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:9e9ca370f717997cb85606d074b0e5b247282cf5e2e1611568b8821afe0342d6"}, + {file = "tornado-6.5.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b77e9dfa7ed69754a54c89d82ef746398be82f749df69c4d3abe75c4d1ff4888"}, + {file = "tornado-6.5.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253b76040ee3bab8bcf7ba9feb136436a3787208717a1fb9f2c16b744fba7331"}, + {file = "tornado-6.5.1-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:308473f4cc5a76227157cdf904de33ac268af770b2c5f05ca6c1161d82fdd95e"}, + {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:caec6314ce8a81cf69bd89909f4b633b9f523834dc1a352021775d45e51d9401"}, + {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:13ce6e3396c24e2808774741331638ee6c2f50b114b97a55c5b442df65fd9692"}, + {file = "tornado-6.5.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5cae6145f4cdf5ab24744526cc0f55a17d76f02c98f4cff9daa08ae9a217448a"}, + {file = "tornado-6.5.1-cp39-abi3-win32.whl", hash = "sha256:e0a36e1bc684dca10b1aa75a31df8bdfed656831489bc1e6a6ebed05dc1ec365"}, + {file = "tornado-6.5.1-cp39-abi3-win_amd64.whl", hash = "sha256:908e7d64567cecd4c2b458075589a775063453aeb1d2a1853eedb806922f568b"}, + {file = "tornado-6.5.1-cp39-abi3-win_arm64.whl", hash = "sha256:02420a0eb7bf617257b9935e2b754d1b63897525d8a289c9d65690d580b4dcf7"}, + {file = "tornado-6.5.1.tar.gz", hash = "sha256:84ceece391e8eb9b2b95578db65e920d2a61070260594819589609ba9bc6308c"}, ] [[package]] name = "tox" -version = "4.24.2" +version = "4.27.0" description = "tox is a generic virtualenv management and test command line tool" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "tox-4.24.2-py3-none-any.whl", hash = "sha256:92e8290e76ad4e15748860a205865696409a2d014eedeb796a34a0f3b5e7336e"}, - {file = "tox-4.24.2.tar.gz", hash = "sha256:d5948b350f76fae436d6545a5e87c2b676ab7a0d7d88c1308651245eadbe8aea"}, + {file = "tox-4.27.0-py3-none-any.whl", hash = "sha256:2b8a7fb986b82aa2c830c0615082a490d134e0626dbc9189986da46a313c4f20"}, + {file = "tox-4.27.0.tar.gz", hash = "sha256:b97d5ecc0c0d5755bcc5348387fef793e1bfa68eb33746412f4c60881d7f5f57"}, ] [package.dependencies] @@ -7257,7 +7604,7 @@ pluggy = ">=1.5" pyproject-api = ">=1.8" tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} typing-extensions = {version = ">=4.12.2", markers = "python_version < \"3.11\""} -virtualenv = ">=20.29.1" +virtualenv = ">=20.31" [package.extras] test = ["devpi-process (>=1.0.2)", "pytest (>=8.3.4)", "pytest-mock (>=3.14)"] @@ -7326,15 +7673,15 @@ test = ["absl-py (>=1.4.0)", "jax (>=0.4.23)", "omegaconf (>=2.0.0)", "pydantic [[package]] name = "trimesh" -version = "4.6.5" +version = "4.6.13" description = "Import, export, process, analyze and view triangular meshes." optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\" or extra == \"trimesh\" or extra == \"heatcharge\"" files = [ - {file = "trimesh-4.6.5-py3-none-any.whl", hash = "sha256:17c423658e4504358f6c3abd45fe921f09ad3ad2fc2578d89608af2f2d56bc5e"}, - {file = "trimesh-4.6.5.tar.gz", hash = "sha256:19a6ea2ad18f8db8bde47ffb3deccb6cddb4d5de717f9b3df47932954f86ee8c"}, + {file = "trimesh-4.6.13-py3-none-any.whl", hash = "sha256:b20b4c3ff03d185ec5b2b0e3adce6e75d8d73508861f2c1be3e40ab47cf18fee"}, + {file = "trimesh-4.6.13.tar.gz", hash = "sha256:2950dd6c3c9c9948a652f7a2966319b47130467bbbf447b254e02b9d90c94f14"}, ] [package.dependencies] @@ -7342,68 +7689,87 @@ numpy = ">=1.20" [package.extras] all = ["trimesh[deprecated,easy,recommend,test,test-more]"] -deprecated = ["gmsh (==4.12.2)"] -easy = ["charset-normalizer", "colorlog", "embreex ; platform_machine == \"x86_64\"", "httpx", "jsonschema", "lxml", "manifold3d (>=2.3.0)", "mapbox_earcut (>=1.0.2) ; python_version >= \"3.9\"", "networkx", "pillow", "pycollada", "rtree", "scipy", "shapely", "svg.path", "vhacdx ; python_version >= \"3.9\"", "xatlas", "xxhash"] -recommend = ["cascadio", "fast-simplification", "meshio", "openctm ; platform_machine == \"x86_64\"", "psutil", "pyglet (<2)", "python-fcl", "scikit-image", "sympy"] +deprecated = ["gmsh (==4.12.2)", "openctm"] +easy = ["charset-normalizer", "colorlog", "embreex ; platform_machine == \"x86_64\"", "httpx", "jsonschema", "lxml", "manifold3d (>=2.3.0)", "mapbox_earcut (>=1.0.2) ; python_version >= \"3.9\"", "networkx", "pillow", "pycollada", "rtree", "scipy", "shapely", "svg.path", "vhacdx ; python_version >= \"3.9\"", "xxhash"] +recommend = ["cascadio", "fast-simplification", "meshio", "psutil", "pyglet (<2)", "python-fcl", "scikit-image", "sympy"] test = ["pyinstrument", "pytest", "pytest-cov", "ruff"] -test-more = ["coveralls", "ezdxf", "ipython", "matplotlib", "pymeshlab", "pyright", "pytest-beartype ; python_version >= \"3.10\"", "triangle"] +test-more = ["coveralls", "ezdxf", "ipython", "marimo", "matplotlib", "pymeshlab", "pyright", "pytest-beartype ; python_version >= \"3.10\"", "triangle", "xatlas"] [[package]] name = "triton" -version = "3.2.0" +version = "3.3.1" description = "A language and compiler for custom Deep Learning operations" optional = true python-versions = "*" groups = ["main"] markers = "(extra == \"dev\" or extra == \"pytorch\") and platform_system == \"Linux\" and platform_machine == \"x86_64\" and sys_platform == \"darwin\"" files = [ - {file = "triton-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3e54983cd51875855da7c68ec05c05cf8bb08df361b1d5b69e05e40b0c9bd62"}, - {file = "triton-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8009a1fb093ee8546495e96731336a33fb8856a38e45bb4ab6affd6dbc3ba220"}, - {file = "triton-3.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d9b215efc1c26fa7eefb9a157915c92d52e000d2bf83e5f69704047e63f125c"}, - {file = "triton-3.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5dfa23ba84541d7c0a531dfce76d8bcd19159d50a4a8b14ad01e91734a5c1b0"}, - {file = "triton-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ceed0eff2c4a73b14eb63e052992f44bbdf175f3fad21e1ac8097a772de7ee"}, + {file = "triton-3.3.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b74db445b1c562844d3cfad6e9679c72e93fdfb1a90a24052b03bb5c49d1242e"}, + {file = "triton-3.3.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b31e3aa26f8cb3cc5bf4e187bf737cbacf17311e1112b781d4a059353dfd731b"}, + {file = "triton-3.3.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9999e83aba21e1a78c1f36f21bce621b77bcaa530277a50484a7cb4a822f6e43"}, + {file = "triton-3.3.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b89d846b5a4198317fec27a5d3a609ea96b6d557ff44b56c23176546023c4240"}, + {file = "triton-3.3.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a3198adb9d78b77818a5388bff89fa72ff36f9da0bc689db2f0a651a67ce6a42"}, + {file = "triton-3.3.1-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f6139aeb04a146b0b8e0fbbd89ad1e65861c57cfed881f21d62d3cb94a36bab7"}, ] +[package.dependencies] +setuptools = ">=40.8.0" + [package.extras] build = ["cmake (>=3.20)", "lit"] -tests = ["autopep8", "flake8", "isort", "llnl-hatchet", "numpy", "pytest", "scipy (>=1.7.1)"] +tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"] tutorials = ["matplotlib", "pandas", "tabulate"] [[package]] name = "types-python-dateutil" -version = "2.9.0.20241206" +version = "2.9.0.20250708" description = "Typing stubs for python-dateutil" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, - {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, + {file = "types_python_dateutil-2.9.0.20250708-py3-none-any.whl", hash = "sha256:4d6d0cc1cc4d24a2dc3816024e502564094497b713f7befda4d5bc7a8e3fd21f"}, + {file = "types_python_dateutil-2.9.0.20250708.tar.gz", hash = "sha256:ccdbd75dab2d6c9696c350579f34cffe2c281e4c5f27a585b2a2438dd1d5c8ab"}, ] [[package]] name = "typing-extensions" -version = "4.12.2" -description = "Backported and Experimental Type Hints for Python 3.8+" +version = "4.14.1" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, + {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" groups = ["main"] files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, ] +[package.dependencies] +typing-extensions = ">=4.12.0" + [[package]] name = "tzdata" -version = "2025.1" +version = "2025.2" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" groups = ["main"] files = [ - {file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"}, - {file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"}, + {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, + {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, ] [[package]] @@ -7442,15 +7808,15 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.3.0" +version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main"] markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, - {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] [package.extras] @@ -7461,15 +7827,15 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.29.3" +version = "20.31.2" description = "Virtual Python Environment builder" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170"}, - {file = "virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac"}, + {file = "virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11"}, + {file = "virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af"}, ] [package.dependencies] @@ -7479,40 +7845,46 @@ platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] [[package]] name = "vtk" -version = "9.4.1" +version = "9.5.0" description = "VTK is an open-source toolkit for 3D computer graphics, image processing, and visualization" optional = true python-versions = "*" groups = ["main"] markers = "extra == \"dev\" or extra == \"vtk\" or extra == \"heatcharge\"" files = [ - {file = "vtk-9.4.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:37bcde65ffcf0f427ebf71c9d77f0c6efc7dbc57f1fe7d2fb904730d89ddf159"}, - {file = "vtk-9.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:950130df308043359c42c8ef7e2d5df55a7ba9baf60e544b304e8c46ab606979"}, - {file = "vtk-9.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e833ddfe9879807ddf8c7a66fedfc23004bafd2f0e243484aaa37be6392df2d"}, - {file = "vtk-9.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bdd18f0c0c72ec2753b8f06466352d17a9246f85955eb0893874829f50b4614"}, - {file = "vtk-9.4.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:81d548223811fc40570b1a97a788b9d16ef782fafead5d4d6c3ec71e48346962"}, - {file = "vtk-9.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc6997d7b250f9ea1108b2b83237faa3f7c5bfcb6277b69ea92b1fdc46bc7140"}, - {file = "vtk-9.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cad713bed5004b68dfb9d46873aac15df9af827796d2a6f0fcafaea9ae2a3989"}, - {file = "vtk-9.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fefc2caf74f3444490ed806053912e18cbc5d0a5a2b5d02fddff16fe31b8ea3a"}, - {file = "vtk-9.4.1-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:0ba2e5782fa789d39bfe157f67e147693bec89d2e33184952bea1ef8ede16141"}, - {file = "vtk-9.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a8427dbaa3248a5629d3cd20af8d1f99c89e7ed58b9b03b8eda2a98d0c3bd98"}, - {file = "vtk-9.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d14573192ef90cefe040768e3ebf3c42810e4ed120794794067cd217686812f"}, - {file = "vtk-9.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:4dc25985b8be5f3fa0a9f4d6d7acf570eb4174bef3f38e28c8071a9d85588fb2"}, - {file = "vtk-9.4.1-cp313-cp313-macosx_10_10_x86_64.whl", hash = "sha256:62799051c11dcffd6602eee2bbe5044399dd660fd5da01c516722409e3efdcc9"}, - {file = "vtk-9.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d96c5c56947e73d133878beab8b5a64cab4f1417840e19ce379c733de976ec77"}, - {file = "vtk-9.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4710e29b38f569f3f4ab2bbd9672c13c5f506a8bb774bed122d4f4ae5d5462dd"}, - {file = "vtk-9.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:852690a80c10775aa29399c0be2dba65f0a5f3de480244fef7920968a69c960b"}, - {file = "vtk-9.4.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:5852cc27ac33b21040e6531dd0f8479e25898dc6c5665c0028e72e8f2afb99f7"}, - {file = "vtk-9.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3d87afa49d54eb775cb43e1375c24d1666a6b244080d44a8242091aa567b858"}, - {file = "vtk-9.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0854c33ae411b14f359d7ab7e5c9e400985ff430b0171e12455a772824049f19"}, - {file = "vtk-9.4.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:f7219822a1a88f9f50710d2f8874dad533fcc92165657f2bb071a9771b63b651"}, - {file = "vtk-9.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f396dde48665702df2514ebe8284e43e35cf68590bdab55b1001fd52ce52e7bf"}, - {file = "vtk-9.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9b5e0af140c2e9bac1f59688ee0996780c2f0f581de00169e4f50116328221"}, - {file = "vtk-9.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:bb84306ffd48ee93fd785334c93687ef3590a737fa242e4d46148c58ed6c4860"}, + {file = "vtk-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:f9ed7461707bc2b5b2cca6eb3a749de82269ba632ab39a5e0f3b55e3d5002ff8"}, + {file = "vtk-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0c1e235d6e2c98ad38ddfa24c71aef002ee203cdf2edd7fb0ac8c215e899fcb"}, + {file = "vtk-9.5.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13e9cb8b370a4036c207d49c5e587035d9d041f5fe95de94a0f3103491480cba"}, + {file = "vtk-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:28edfb69202e17e3fa07ae7d6179243415ff8c61befaac31a3385a80c3d5b4a8"}, + {file = "vtk-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:84ffda07506d5ac1b969bce9cc264577bd58752b62cf308ae55f007d0805f6b6"}, + {file = "vtk-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8b94c3899c9f59bd25055e36695e9056babb38dc743ac59ce483f281b0ddf022"}, + {file = "vtk-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7d1afc47c3243c47daa04de5f80d2b18718d31a779c55346c653f0cae9d522"}, + {file = "vtk-9.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7676ca7ea2800a9ce377e0e475e7f0956f5d034031ca3bff3b3e584e9aee61c8"}, + {file = "vtk-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:202e740c10614428ba7e000a15dd08fccdfbf1c6cf9577b28e664d2840576c68"}, + {file = "vtk-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:5894fd1b228d456678c89bf847ebdc8441ea3ae73514d2da40dd1713428912c6"}, + {file = "vtk-9.5.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:27f47c46279bf11645a9d7190c28301653f0231c5191001a75c4bc1119898ea6"}, + {file = "vtk-9.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:96edbea916507c397f4ac5ae32ff706a109b7fbcf3d38c2fe8a47b34afe2e96e"}, + {file = "vtk-9.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa229223771e55c50704d0fdae9f17f1991d588d4169935127e6bbf1d437c4b"}, + {file = "vtk-9.5.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:879256ccbb65d12904ca3f9159cfca1c3812d605ee3062c9c04acf5c6f812164"}, + {file = "vtk-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea4fc23ddf7f12021dbbf116f5f764240a2774ad1df2e7655191ca599093080d"}, + {file = "vtk-9.5.0-cp313-cp313-macosx_10_10_x86_64.whl", hash = "sha256:8a7511d161edefa1fae5035483ccff486473e60970b231566e3dbcaf567554ac"}, + {file = "vtk-9.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c9a3028c47d2c91d3ca3188b4815de1bcf9af88492eeceee67fd25a0aeeaa195"}, + {file = "vtk-9.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:31aee64ff6d328997f6e1fc9ac4378551311b8c7d2c00cec18e62f7980103d92"}, + {file = "vtk-9.5.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:bbf7bd211caf0ee36a3478dae918ca81daaf481f2d98c87ae60aa5f2500e483f"}, + {file = "vtk-9.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:f6ea8516a6ac4910bc8d5291f70a1cf5015b2d57e24005b88f8d9c1d303638d7"}, + {file = "vtk-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:feef505601b0c76d65e23490f4d5afab0f7b560e8ad041923b9fb4a78e7c4dac"}, + {file = "vtk-9.5.0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bd0772b8492cc47f9b41c615c8cfc5d8f839cfb9cb54470b25cbf46864d98809"}, + {file = "vtk-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:944a05167ffb669e76a05257bd7ed7382e51da2551895b91d7672bd4187327d2"}, + {file = "vtk-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:cd640faf9753c2f9ac99c82ce7563bf02bd982b846e633297d1ba61e6a9fa3d9"}, + {file = "vtk-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:ee27f2bb31b1b19e88061b31ec85b7bb318b7195203352afdd4f6ba6f38cba78"}, + {file = "vtk-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c79ad52aed7fc5662e708de3918778bc33e4f94cea99174ef0a2461869b95ce7"}, + {file = "vtk-9.5.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b9a6b5eb422cc089aa6f882b7261d4c888ee423aacd274085c2d5a9eba5c14e"}, + {file = "vtk-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:aa629462f8b2b77b7b88962cda4d806e6868b64b1f21d5a4c6a08cdfbc2ae0ec"}, + {file = "vtk-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:74143ce3adc40342ce4c44dd3a319b376d5dee745e19ff20dea3cabe1f13915d"}, ] [package.dependencies] @@ -7524,37 +7896,21 @@ web = ["wslink (>=1.0.4)"] [[package]] name = "wadler-lindig" -version = "0.1.4" +version = "0.1.7" description = "A Wadler–Lindig pretty-printer for Python." optional = true python-versions = ">=3.10" groups = ["main"] markers = "python_version >= \"3.10\" and (extra == \"dev\" or extra == \"docs\")" files = [ - {file = "wadler_lindig-0.1.4-py3-none-any.whl", hash = "sha256:5c463aeb1f4ddc4acc12c3708d22ae21bcfc3e19e7c4d7aeef6642ea57b1a8b8"}, - {file = "wadler_lindig-0.1.4.tar.gz", hash = "sha256:75aa3ddd384573c41d5c910fd990e655c2a641e5093cf5081650d0229daf87ad"}, + {file = "wadler_lindig-0.1.7-py3-none-any.whl", hash = "sha256:e3ec83835570fd0a9509f969162aeb9c65618f998b1f42918cfc8d45122fe953"}, + {file = "wadler_lindig-0.1.7.tar.gz", hash = "sha256:81d14d3fe77d441acf3ebd7f4aefac20c74128bf460e84b512806dccf7b2cd55"}, ] [package.extras] dev = ["numpy", "pre-commit", "pytest"] docs = ["hippogriffe (==0.1.0)", "mkdocs (==1.6.1)", "mkdocs-include-exclude-files (==0.1.0)", "mkdocs-ipynb (==0.1.0)", "mkdocs-material (==9.6.7)", "mkdocstrings[python] (==0.28.3)", "pymdown-extensions (==10.14.3)"] -[[package]] -name = "wcmatch" -version = "10.0" -description = "Wildcard/glob file name matcher." -optional = true -python-versions = ">=3.8" -groups = ["main"] -markers = "extra == \"dev\"" -files = [ - {file = "wcmatch-10.0-py3-none-any.whl", hash = "sha256:0dd927072d03c0a6527a20d2e6ad5ba8d0380e60870c383bc533b71744df7b7a"}, - {file = "wcmatch-10.0.tar.gz", hash = "sha256:e72f0de09bba6a04e0de70937b0cf06e55f36f37b3deb422dfaf854b867b840a"}, -] - -[package.dependencies] -bracex = ">=2.1.1" - [[package]] name = "wcwidth" version = "0.2.13" @@ -7614,15 +7970,15 @@ test = ["websockets"] [[package]] name = "widgetsnbextension" -version = "4.0.13" +version = "4.0.14" description = "Jupyter interactive widgets for Jupyter Notebook" optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\" or extra == \"docs\"" files = [ - {file = "widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71"}, - {file = "widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6"}, + {file = "widgetsnbextension-4.0.14-py3-none-any.whl", hash = "sha256:4875a9eaf72fbf5079dc372a51a9f268fc38d46f767cbf85c43a36da5cb9b575"}, + {file = "widgetsnbextension-4.0.14.tar.gz", hash = "sha256:a3629b04e3edb893212df862038c7232f62973373869db5084aed739b437b5af"}, ] [[package]] @@ -7653,15 +8009,15 @@ viz = ["matplotlib", "nc-time-axis", "seaborn"] [[package]] name = "xarray" -version = "2025.3.0" +version = "2025.6.1" description = "N-D labeled arrays and datasets in Python" optional = false python-versions = ">=3.10" groups = ["main"] -markers = "python_version >= \"3.10\"" +markers = "python_version == \"3.10\"" files = [ - {file = "xarray-2025.3.0-py3-none-any.whl", hash = "sha256:022b7eac5ebc26d70d34211de732ec1a15127a40455f9492acdde7fbe5bbf091"}, - {file = "xarray-2025.3.0.tar.gz", hash = "sha256:531cf6d64e6ab54c19239930a840654f1a79d2140e9f0d11d1e8d69dcc581d0f"}, + {file = "xarray-2025.6.1-py3-none-any.whl", hash = "sha256:8b988b47f67a383bdc3b04c5db475cd165e580134c1f1943d52aee4a9c97651b"}, + {file = "xarray-2025.6.1.tar.gz", hash = "sha256:a84f3f07544634a130d7dc615ae44175419f4c77957a7255161ed99c69c7c8b0"}, ] [package.dependencies] @@ -7675,19 +8031,46 @@ complete = ["xarray[accel,etc,io,parallel,viz]"] etc = ["sparse"] io = ["cftime", "fsspec", "h5netcdf", "netCDF4", "pooch", "pydap ; python_version < \"3.10\"", "scipy", "zarr"] parallel = ["dask[complete]"] -types = ["pandas-stubs", "types-PyYAML", "types-Pygments", "types-colorama", "types-decorator", "types-defusedxml", "types-docutils", "types-networkx", "types-openpyxl", "types-pexpect", "types-psutil", "types-pycurl", "types-python-dateutil", "types-pytz", "types-setuptools"] +types = ["pandas-stubs", "scipy-stubs", "types-PyYAML", "types-Pygments", "types-colorama", "types-decorator", "types-defusedxml", "types-docutils", "types-networkx", "types-openpyxl", "types-pexpect", "types-psutil", "types-pycurl", "types-python-dateutil", "types-pytz", "types-setuptools"] viz = ["cartopy", "matplotlib", "nc-time-axis", "seaborn"] +[[package]] +name = "xarray" +version = "2025.7.0" +description = "N-D labeled arrays and datasets in Python" +optional = false +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\"" +files = [ + {file = "xarray-2025.7.0-py3-none-any.whl", hash = "sha256:7b5d7267bd554ae119c7a0062f62b50517b4dd1968efc11f2553826b7d99297f"}, + {file = "xarray-2025.7.0.tar.gz", hash = "sha256:fd83ac8d638e7caef9d7f0c82bcdf380cede29d2ff84575133b2b95164af78ee"}, +] + +[package.dependencies] +numpy = ">=1.26" +packaging = ">=24.1" +pandas = ">=2.2" + +[package.extras] +accel = ["bottleneck", "flox (>=0.9)", "numba (>=0.59)", "numbagg (>=0.8)", "opt_einsum", "scipy (>=1.13)"] +complete = ["xarray[accel,etc,io,parallel,viz]"] +etc = ["sparse (>=0.15)"] +io = ["cftime", "fsspec", "h5netcdf", "netCDF4 (>=1.6.0)", "pooch", "pydap", "scipy (>=1.13)", "zarr (>=2.18)"] +parallel = ["dask[complete]"] +types = ["pandas-stubs", "scipy-stubs", "types-PyYAML", "types-Pygments", "types-colorama", "types-decorator", "types-defusedxml", "types-docutils", "types-networkx", "types-openpyxl", "types-pexpect", "types-psutil", "types-pycurl", "types-python-dateutil", "types-pytz", "types-setuptools"] +viz = ["cartopy (>=0.23)", "matplotlib", "nc-time-axis", "seaborn"] + [[package]] name = "zipp" -version = "3.21.0" +version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, - {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] @@ -7695,15 +8078,14 @@ check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \" cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] enabler = ["pytest-enabler (>=2.2)"] -test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] type = ["pytest-mypy"] [extras] adjoint = ["jax", "jaxlib"] design = ["bayesian-optimization", "pygad", "pyswarms"] -dev = ["bayesian-optimization", "bump-my-version", "cma", "coverage", "devsim", "dill", "gdspy", "gdstk", "grcwa", "ipython", "ipython", "jax", "jaxlib", "jinja2", "jupyter", "memory_profiler", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "networkx", "optax", "pre-commit", "psutil", "pydata-sphinx-theme", "pygad", "pylint", "pyswarms", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "rtree", "ruff", "sax", "scikit-rf", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm", "torch", "torch", "tox", "trimesh", "vtk"] +dev = ["bayesian-optimization", "cma", "coverage", "devsim", "diff-cover", "dill", "gdstk", "grcwa", "ipython", "ipython", "jax", "jaxlib", "jinja2", "jupyter", "memory_profiler", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "networkx", "optax", "pre-commit", "psutil", "pydata-sphinx-theme", "pygad", "pylint", "pyswarms", "pytest", "pytest-cov", "pytest-env", "pytest-timeout", "pytest-xdist", "rtree", "ruff", "sax", "scikit-rf", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm", "torch", "torch", "tox", "trimesh", "vtk"] docs = ["cma", "devsim", "gdstk", "grcwa", "ipython", "jinja2", "jupyter", "myst-parser", "nbconvert", "nbdime", "nbsphinx", "optax", "pydata-sphinx-theme", "pylint", "sax", "signac", "sphinx", "sphinx-book-theme", "sphinx-copybutton", "sphinx-design", "sphinx-favicon", "sphinx-notfound-page", "sphinx-sitemap", "sphinx-tabs", "sphinxemoji", "tmm"] -gdspy = ["gdspy"] gdstk = ["gdstk"] heatcharge = ["devsim", "trimesh", "vtk"] pytorch = ["torch", "torch"] @@ -7715,4 +8097,4 @@ vtk = ["vtk"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<3.14" -content-hash = "c948357280c9ae9288903051ab031ae58db5daca58c12221a51143b2558eca07" +content-hash = "7432868ecaf28a1207146ad2ec44562a30486cc69e998c6cd9e4db56679edc78" diff --git a/pyproject.toml b/pyproject.toml index 22e17c5633..38db4f28a4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "tidy3d" -version = "2.8.4" +version = "2.9.0" description = "A fast FDTD solver" authors = ["Tyler Hughes "] license = "LGPLv2+" @@ -17,6 +17,7 @@ classifiers = [ "Operating System :: OS Independent", ] documentation = "https://docs.flexcompute.com/projects/tidy3d/en/latest/" +include = [{ path = "tidy3d/style.mplstyle", format = ["sdist", "wheel"] }] [tool.poetry.urls] "Bug Tracker" = "https://github.com/flexcompute/tidy3d/issues" @@ -50,8 +51,7 @@ joblib = "*" ### Optional dependencies ### # development core -bump-my-version = { version = "*", optional = true } -ruff = { version = "0.5.5", optional = true } +ruff = { version = "0.11.11", optional = true } coverage = { version = "*", optional = true } dill = { version = "*", optional = true } ipython = { version = "*", optional = true } @@ -65,9 +65,7 @@ pytest-xdist = "^3.6.1" pytest-cov = "^6.0.0" pytest-env = "^1.1.5" tox = { version = "*", optional = true } - -# gdspy -gdspy = { version = "*", optional = true } +diff-cover = { version = "*", optional = true } # gdstk gdstk = { version = ">=0.9.49", optional = true } @@ -85,8 +83,8 @@ pyswarms = { version = "*", optional = true } # pytorch torch = [ - { version = "^2.2.0", source = "PyPI", platform = "darwin", optional = true }, - { version = "^2.2.0", source = "torch-cpu", platform = "!=darwin", optional = true }, + { version = "^2.2.0", source = "PyPI", platform = "darwin", optional = true }, + { version = "^2.2.0", source = "torch-cpu", platform = "!=darwin", optional = true }, ] # scikit-rf @@ -128,11 +126,9 @@ cma = { version = "*", optional = true } [tool.poetry.extras] dev = [ 'bayesian-optimization', - 'bump-my-version', "coverage", 'dill', 'divparams', - 'gdspy', 'gdstk', 'grcwa', 'ipython', @@ -180,6 +176,7 @@ dev = [ 'vtk', 'devsim', 'cma', + 'diff-cover' ] docs = [ "jupyter", @@ -210,7 +207,6 @@ docs = [ "devsim", "cma", ] -gdspy = ["gdspy"] gdstk = ["gdstk"] scikit-rf = ["scikit-rf"] trimesh = ["trimesh", "networkx", "rtree"] @@ -249,38 +245,62 @@ line-length = 100 extend-exclude = ["docs/faq/", "docs/notebooks/"] [tool.ruff.lint] -typing-modules = [ - "tidy3d.components.types", -] # without this Literal["something fails"] -select = [ - "I", # isort +extend-select = [ "E", # pycodestyle errors - "W", # pycodestyle warnings "F", # pyflakes - "C", # flake8-comprehensions - "B", # flake8-bugbear - "UP", - "NPY201", # numpy 2.* compatibility check + "B", # bugbear + "I", # isort + "UP", # pyupgrade + "W", # pycodestyle + "C4", # flake8-comprehensions + "NPY", # numpy-specific rules + "RUF", # ruff builtins + "ISC", # implicit string concatenation + "PIE", # flake8-pie + "RSE", # unnecessary parantheses on raised exceptions + "TID", # no relative imports from parent modules + "PLE", # pylint errors + "PLC", # pylint conventions +] +extend-ignore = [ + "RUF001", # ambiguous unicode characters + "RUF002", # ambiguous unicode characters + "RUF003", # ambiguous unicode characters + "RUF012", # type hints for mutable defaults + "RUF015", # next(iter(...)) instead of list(...)[0] + "E501", # line too long + "B905", # `zip()` without an explicit `strict=` parameter + "UP007", # TODO: Remove once Python >= 3.10 + "NPY002", # TODO: Revisit RNG handling +] + +[tool.ruff.lint.isort] +required-imports = ["from __future__ import annotations"] + +[tool.ruff.lint.flake8-tidy-imports] +banned-module-level-imports = ["scipy", "matplotlib"] + +[tool.ruff.lint.per-file-ignores] +"tests/**/*" = [ + "B015", # useless comparison + "B018", # useless expression + "E402", # module-level import not at top of file + "E731", # lambda assignment + "F841", # unused local variable + "S101", # asserts allowed in tests + "NPY201", # numpy 2.* compatibility check + "TID252", # allow relative imports in tests + "TID253", # allow heavy imports in tests ] -ignore = [ - "E501", - "B008", # do not perform function calls in argument defaults - "C901", # too complex - "UP007", # use x | y instead of union[x,y] (does not work) - "B905", # `zip()` without an explicit `strict=` parameter - "C408", # C408 Unnecessary `dict` call (rewrite as a literal) - "B904", - "B028", # stacklevel - "UP006", # typy annotation with Tuple[float] messes up pydantic - "UP038", # TODO decide what to do here - "UP035", # TODO decide what to do here +"tidy3d/plugins/**/*" = [ + "TID253", # allow heavy imports in plugins (not used by MC) ] [tool.pytest.ini_options] # TODO: remove --assert=plain when https://github.com/scipy/scipy/issues/22236 is resolved addopts = "--cov=tidy3d --doctest-modules -n auto --dist worksteal --assert=plain -m 'not numerical' " markers = [ - "numerical: marks numerical tests for adjoint gradients that require running simulations (deselect with '-m \"not numerical\"')", + "numerical: marks numerical tests for adjoint gradients that require running simulations (deselect with '-m \"not numerical\"')", ] env = ["MPLBACKEND=Agg", "OMP_NUM_THREADS=1"] doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS" @@ -296,42 +316,3 @@ norecursedirs = [ filterwarnings = "ignore::DeprecationWarning" testpaths = ["tidy3d", "tests", "docs"] python_files = "*.py" - -[tool.bumpversion] -current_version = "2.8.4" -parse = """(?x) - (?P0|[1-9]\\d*)\\. - (?P0|[1-9]\\d*)\\. - (?P0|[1-9]\\d*) - (?: - (?P[a-zA-Z-]+) # pre-release label - (?P0|[1-9]\\d*) # pre-release version number - )? # pre-release section is optional -""" -serialize = ["{major}.{minor}.{patch}{pre_l}{pre_n}", "{major}.{minor}.{patch}"] -search = "{current_version}" -replace = "{new_version}" -regex = false -ignore_missing_version = true -ignore_missing_files = false -tag = false -sign_tags = false -tag_name = "v{new_version}" -tag_message = "Bump version: {current_version} → {new_version}" -allow_dirty = false -commit = false -message = "Bump version: {current_version} → {new_version}" -commit_args = "" - -[tool.bumpversion.parts.pre_l] -values = ["rc", ""] - -[[tool.bumpversion.files]] -filename = "pyproject.toml" -search = "\nversion = \"{current_version}\"" -replace = "\nversion = \"{new_version}\"" - -[[tool.bumpversion.files]] -filename = "tidy3d/version.py" -search = "{current_version}" -replace = "{new_version}" diff --git a/schemas/EMESimulation.json b/schemas/EMESimulation.json new file mode 100644 index 0000000000..c452635fd8 --- /dev/null +++ b/schemas/EMESimulation.json @@ -0,0 +1,13570 @@ +{ + "title": "EMESimulation", + "description": "EigenMode Expansion (EME) simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. \nsources : Tuple[NoneType, ...] = ()\n Sources in the simulation. NOTE: sources are not currently supported for EME simulations. Instead, the simulation performs full bidirectional propagation in the 'port_mode' basis. After running the simulation, use 'smatrix_in_basis' to use another set of modes or input field.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), y=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), z=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. By default, PEC boundary conditions are applied on all sides. This field is for consistency with FDTD simulations; however, please note that regardless of the 'boundary_spec', the mode solver terminates the mode plane with PEC boundary. The 'EMEModeSpec' can be used to apply PML layers in the mode solver.\nmonitors : Tuple[Annotated[Union[tidy3d.components.eme.monitor.EMEModeSolverMonitor, tidy3d.components.eme.monitor.EMEFieldMonitor, tidy3d.components.eme.monitor.EMECoefficientMonitor, tidy3d.components.monitor.ModeSolverMonitor, tidy3d.components.monitor.PermittivityMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions. This is distinct from 'eme_grid_spec', which defines the 1D EME grid in the propagation direction.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.\nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Frequencies for the EME simulation. The field is propagated independently at each provided frequency. This can be slow when the number of frequencies is large. In this case, consider using the approximate 'EMEFreqSweep' as the 'sweep_spec' instead of providing all desired frequencies here.\naxis : Literal[0, 1, 2]\n Propagation axis (0, 1, or 2) for the EME simulation.\neme_grid_spec : Union[EMEUniformGrid, EMECompositeGrid, EMEExplicitGrid]\n Specification for the EME propagation grid. The simulation is divided into cells in the propagation direction; this parameter specifies the layout of those cells. Mode solving is performed in each cell, and then propagation between cells is performed to determine the complete solution. This is distinct from 'grid_spec', which defines the grid in the two tangential directions, as well as the grid used for field monitors.\nstore_port_modes : bool = True\n Whether to store the modes associated with the two ports. Required to find scattering matrix in basis besides the computational basis.\nnormalize : bool = True\n Whether to normalize the port modes to unity flux, thereby normalizing the scattering matrix and expansion coefficients.\nport_offsets : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Offsets for the two ports, relative to the simulation bounds along the propagation axis.\nsweep_spec : Union[EMELengthSweep, EMEModeSweep, EMEFreqSweep, EMEPeriodicitySweep, NoneType] = None\n Specification for a parameter sweep to be performed during the EME propagation step. The results are stored in 'sim_data.smatrix'. Other simulation monitor data is not included in the sweep.\nconstraint : Optional[Literal['passive', 'unitary']] = passive\n Constraint for EME propagation, imposed at cell interfaces. A constraint of 'passive' means that energy can be dissipated but not created at interfaces. A constraint of 'unitary' means that energy is conserved at interfaces (but not necessarily within cells). The option 'none' may be faster for a large number of modes. The option 'passive' can serve as regularization for the field continuity requirement and give more physical results.\n\nNotes\n-----\n\n EME is a frequency-domain method for propagating the electromagnetic field along a\n specified axis. The method is well-suited for propagation of guided waves.\n The electromagnetic fields are expanded locally in the basis of eigenmodes of the\n waveguide; they are then propagated by imposing continuity conditions in this basis.\n\n The EME simulation is performed along the propagation axis ``axis`` at frequencies ``freqs``.\n The simulation is divided into cells along the propagation axis, as defined by\n ``eme_grid_spec``. Mode solving is performed at cell centers, and boundary conditions are\n imposed between cells. The EME ports are defined to be the boundaries of the first and last\n cell in the EME grid. These can be moved using ``port_offsets``.\n\n An EME simulation always computes the full scattering matrix of the structure.\n Additional data can be recorded by adding 'monitors' to the simulation.\n\n **Other Bases**\n\n By default, the scattering matrix is expressed in the basis of EME modes at the two ports. It is sometimes useful to use alternative bases. For example, in a waveguide splitter, we might want the scattering matrix in the basis of modes of the individual waveguides. The functions `smatrix_in_basis` and `field_in_basis` in :class:`.EMESimulationData` can be used for this purpose after the simulation has been run.\n\n **Frequency Sweeps**\n\n Frequency sweeps are supported by including multiple frequencies in the `freqs` field. However, our EME solver repeats the mode solving for each new frequency, so frequency sweeps involving a large number of frequencies can be slow and expensive. If a large number of frequencies are required, consider using our FDTD solver instead.\n\n **Passivity and Unitarity Constraints**\n\n Passivity and unitarity constraints can be imposed via the `constraint` field. These constraints are imposed at interfaces between cells, possibly at the expense of field continuity. Passivity means that the interface can only dissipate energy, and unitarity means the interface will conserve energy (energy may still be dissipated inside cells when the propagation constant is complex). Adding constraints can slow down the simulation significantly, especially for a large number of modes (more than 30 or 40).\n\n **Too Many Modes**\n\n It is important to use enough modes to capture the physics of the device and to ensure that the results have converged (see below). However, using too many modes can slow down the simulation and result in numerical issues. If too many modes are used, it is common to see a warning about invalid modes in the simulation log. While these modes are not included in the EME propagation, this can indicate some other issue with the setup, especially if the results have not converged. In this case, extending the simulation size in the transverse directions and increasing the grid resolution may help by creating more valid modes that can be used in convergence testing.\n\n **Mode Convergence Sweeps**\n\n It is a good idea to check that the number of modes is large enough by running a mode convergence sweep. This can be done using :class:`.EMEModeSweep`.\n\nExample\n-------\n>>> from tidy3d import Box, Medium, Structure, C_0, inf\n>>> from tidy3d import EMEModeSpec, EMEUniformGrid, GridSpec\n>>> from tidy3d import EMEFieldMonitor\n>>> lambda0 = 1550e-9\n>>> freq0 = C_0 / lambda0\n>>> sim_size = 3*lambda0, 3*lambda0, 3*lambda0\n>>> waveguide_size = (lambda0/2, lambda0, inf)\n>>> waveguide = Structure(\n... geometry=Box(center=(0,0,0), size=waveguide_size),\n... medium=Medium(permittivity=2)\n... )\n>>> eme_grid_spec = EMEUniformGrid(num_cells=5, mode_spec=EMEModeSpec(num_modes=10))\n>>> grid_spec = GridSpec(wavelength=lambda0)\n>>> field_monitor = EMEFieldMonitor(\n... size=(0, sim_size[1], sim_size[2]),\n... name=\"field_monitor\"\n... )\n>>> sim = EMESimulation(\n... size=sim_size,\n... monitors=[field_monitor],\n... structures=[waveguide],\n... axis=2,\n... freqs=[freq0],\n... eme_grid_spec=eme_grid_spec,\n... grid_spec=grid_spec\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `EME Solver Demonstration <../../notebooks/docs/features/eme.rst>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMESimulation", + "enum": [ + "EMESimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to vacuum if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. ", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Sources", + "description": "Sources in the simulation. NOTE: sources are not currently supported for EME simulations. Instead, the simulation performs full bidirectional propagation in the 'port_mode' basis. After running the simulation, use 'smatrix_in_basis' to use another set of modes or input field.", + "default": [], + "type": "array", + "items": { + "type": "null" + } + }, + "boundary_spec": { + "title": "Boundaries", + "description": "Specification of boundary conditions along each dimension. By default, PEC boundary conditions are applied on all sides. This field is for consistency with FDTD simulations; however, please note that regardless of the 'boundary_spec', the mode solver terminates the mode plane with PEC boundary. The 'EMEModeSpec' can be used to apply PML layers in the mode solver.", + "default": { + "attrs": {}, + "x": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "y": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "z": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "type": "BoundarySpec" + }, + "allOf": [ + { + "$ref": "#/definitions/BoundarySpec" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "EMEModeSolverMonitor": "#/definitions/EMEModeSolverMonitor", + "EMEFieldMonitor": "#/definitions/EMEFieldMonitor", + "EMECoefficientMonitor": "#/definitions/EMECoefficientMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor", + "PermittivityMonitor": "#/definitions/PermittivityMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/EMEModeSolverMonitor" + }, + { + "$ref": "#/definitions/EMEFieldMonitor" + }, + { + "$ref": "#/definitions/EMECoefficientMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + }, + { + "$ref": "#/definitions/PermittivityMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Specifications for the simulation grid along each of the three directions. This is distinct from 'eme_grid_spec', which defines the 1D EME grid in the propagation direction.", + "default": { + "attrs": {}, + "grid_x": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_y": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_z": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "wavelength": null, + "override_structures": [], + "snapping_points": [], + "layer_refinement_specs": [], + "type": "GridSpec" + }, + "validate_default": true, + "allOf": [ + { + "$ref": "#/definitions/GridSpec" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "lumped_elements": { + "title": "Lumped Elements", + "description": "Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "LumpedResistor": "#/definitions/LumpedResistor", + "CoaxialLumpedResistor": "#/definitions/CoaxialLumpedResistor", + "LinearLumpedElement": "#/definitions/LinearLumpedElement" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LumpedResistor" + }, + { + "$ref": "#/definitions/CoaxialLumpedResistor" + }, + { + "$ref": "#/definitions/LinearLumpedElement" + } + ] + } + }, + "subpixel": { + "title": "Subpixel Averaging", + "description": "Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.", + "default": { + "attrs": {}, + "dielectric": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "metal": { + "attrs": {}, + "type": "Staircasing" + }, + "pec": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" + }, + "lossy_metal": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "type": "SubpixelSpec" + }, + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/SubpixelSpec" + } + ] + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.", + "default": "tidy3d", + "enum": [ + "autograd_fwd", + "autograd_bwd", + "tidy3d" + ], + "type": "string" + }, + "post_norm": { + "title": "Post Normalization Values", + "description": "Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.", + "default": 1.0, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "freqs": { + "title": "Frequencies", + "description": "Frequencies for the EME simulation. The field is propagated independently at each provided frequency. This can be slow when the number of frequencies is large. In this case, consider using the approximate 'EMEFreqSweep' as the 'sweep_spec' instead of providing all desired frequencies here.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "axis": { + "title": "Propagation Axis", + "description": "Propagation axis (0, 1, or 2) for the EME simulation.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "eme_grid_spec": { + "title": "EME Grid Specification", + "description": "Specification for the EME propagation grid. The simulation is divided into cells in the propagation direction; this parameter specifies the layout of those cells. Mode solving is performed in each cell, and then propagation between cells is performed to determine the complete solution. This is distinct from 'grid_spec', which defines the grid in the two tangential directions, as well as the grid used for field monitors.", + "anyOf": [ + { + "$ref": "#/definitions/EMEUniformGrid" + }, + { + "$ref": "#/definitions/EMECompositeGrid" + }, + { + "$ref": "#/definitions/EMEExplicitGrid" + } + ] + }, + "store_port_modes": { + "title": "Store Port Modes", + "description": "Whether to store the modes associated with the two ports. Required to find scattering matrix in basis besides the computational basis.", + "default": true, + "type": "boolean" + }, + "normalize": { + "title": "Normalize Scattering Matrix", + "description": "Whether to normalize the port modes to unity flux, thereby normalizing the scattering matrix and expansion coefficients.", + "default": true, + "type": "boolean" + }, + "port_offsets": { + "title": "Port Offsets", + "description": "Offsets for the two ports, relative to the simulation bounds along the propagation axis.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "sweep_spec": { + "title": "EME Sweep Specification", + "description": "Specification for a parameter sweep to be performed during the EME propagation step. The results are stored in 'sim_data.smatrix'. Other simulation monitor data is not included in the sweep.", + "anyOf": [ + { + "$ref": "#/definitions/EMELengthSweep" + }, + { + "$ref": "#/definitions/EMEModeSweep" + }, + { + "$ref": "#/definitions/EMEFreqSweep" + }, + { + "$ref": "#/definitions/EMEPeriodicitySweep" + } + ] + }, + "constraint": { + "title": "EME Constraint", + "description": "Constraint for EME propagation, imposed at cell interfaces. A constraint of 'passive' means that energy can be dissipated but not created at interfaces. A constraint of 'unitary' means that energy is conserved at interfaces (but not necessarily within cells). The option 'none' may be faster for a large number of modes. The option 'passive' can serve as regularization for the field continuity requirement and give more physical results.", + "default": "passive", + "enum": [ + "passive", + "unitary" + ], + "type": "string" + } + }, + "required": [ + "size", + "freqs", + "axis", + "eme_grid_spec" + ], + "additionalProperties": false, + "definitions": { + "NonlinearSusceptibility": { + "title": "NonlinearSusceptibility", + "description": "Model for an instantaneous nonlinear chi3 susceptibility.\nThe expression for the instantaneous nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nchi3 : float = 0\n [units = um^2 / V^2]. Chi3 nonlinear susceptibility.\nnumiters : Optional[PositiveInt] = None\n Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\chi_3` must be real.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "NonlinearSusceptibility", + "enum": [ + "NonlinearSusceptibility" + ], + "type": "string" + }, + "chi3": { + "title": "Chi3", + "description": "Chi3 nonlinear susceptibility.", + "default": 0, + "units": "um^2 / V^2", + "type": "number" + }, + "numiters": { + "title": "Number of iterations", + "description": "Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.", + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "additionalProperties": false + }, + "ComplexNumber": { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + "TwoPhotonAbsorption": { + "title": "TwoPhotonAbsorption", + "description": "Model for two-photon absorption (TPA) nonlinearity which gives an intensity-dependent\nabsorption of the form :math:`\\alpha = \\alpha_0 + \\beta I`.\nAlso includes free-carrier absorption (FCA) and free-carrier plasma dispersion (FCPD) effects.\nThe expression for the nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nbeta : Union[float, tidycomplex, ComplexNumber] = 0\n [units = um / W]. Coefficient for two-photon absorption (TPA).\ntau : NonNegativeFloat = 0\n [units = sec]. Lifetime for the free carriers created by two-photon absorption (TPA).\nsigma : NonNegativeFloat = 0\n [units = um^2]. Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.\ne_e : NonNegativeFloat = 1\n Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\ne_h : NonNegativeFloat = 1\n Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_e : float = 0\n [units = um^(3 e_e)]. Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_h : float = 0\n [units = um^(3 e_h)]. Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\nfreq0 : Optional[PositiveFloat] = None\n Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\beta` must be real.\n\n .. math::\n\n P_{NL} = P_{TPA} + P_{FCA} + P_{FCPD} \\\\\n P_{TPA} = -\\frac{4}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{2 i \\omega} |E|^2 E \\\\\n P_{FCA} = -\\frac{c_0 \\varepsilon_0 n_0 \\sigma N_f}{i \\omega} E \\\\\n \\frac{dN_f}{dt} = \\frac{8}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{8 q_e \\hbar \\omega} |E|^4 - \\frac{N_f}{\\tau} \\\\\n N_e = N_h = N_f \\\\\n P_{FCPD} = \\varepsilon_0 2 n_0 \\Delta n (N_f) E \\\\\n \\Delta n (N_f) = (c_e N_e^{e_e} + c_h N_h^{e_h})\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n The implementation is described in::\n\n N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si\n High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> tpa_model = TwoPhotonAbsorption(beta=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TwoPhotonAbsorption", + "enum": [ + "TwoPhotonAbsorption" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "beta": { + "title": "TPA coefficient", + "description": "Coefficient for two-photon absorption (TPA).", + "default": 0, + "units": "um / W", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "tau": { + "title": "Carrier lifetime", + "description": "Lifetime for the free carriers created by two-photon absorption (TPA).", + "default": 0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "sigma": { + "title": "FCA cross section", + "description": "Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.", + "default": 0, + "units": "um^2", + "minimum": 0, + "type": "number" + }, + "e_e": { + "title": "Electron exponent", + "description": "Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "e_h": { + "title": "Hole exponent", + "description": "Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "c_e": { + "title": "Electron coefficient", + "description": "Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_e)", + "type": "number" + }, + "c_h": { + "title": "Hole coefficient", + "description": "Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_h)", + "type": "number" + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "freq0": { + "title": "Central frequency", + "description": "Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "KerrNonlinearity": { + "title": "KerrNonlinearity", + "description": "Model for Kerr nonlinearity which gives an intensity-dependent refractive index\nof the form :math:`n = n_0 + n_2 I`. The expression for the nonlinear polarization\nis given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nn2 : Union[tidycomplex, ComplexNumber] = 0\n [units = um^2 / W]. Nonlinear refractive index in the Kerr nonlinearity.\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\n_2` must be real.\n\n This model is equivalent to a :class:`.NonlinearSusceptibility`; the\n relation between the parameters is given below.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E \\\\\n n_2 = \\frac{3}{4 n_0^2 \\varepsilon_0 c_0} \\chi_3\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n To simulate nonlinear loss, consider instead using a :class:`.TwoPhotonAbsorption`\n model, which implements a more physical dispersive loss of the form\n :math:`\\chi_{TPA} = i \\frac{c_0 n_0 \\beta}{\\omega} I`.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> kerr_model = KerrNonlinearity(n2=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "KerrNonlinearity", + "enum": [ + "KerrNonlinearity" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "n2": { + "title": "Nonlinear refractive index", + "description": "Nonlinear refractive index in the Kerr nonlinearity.", + "default": 0, + "units": "um^2 / W", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "additionalProperties": false + }, + "NonlinearSpec": { + "title": "NonlinearSpec", + "description": "Abstract specification for adding nonlinearities to a medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmodels : Tuple[Union[NonlinearSusceptibility, TwoPhotonAbsorption, KerrNonlinearity], ...] = ()\n The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.\nnum_iters : PositiveInt = 5\n Number of iterations for solving nonlinear constitutive relation.\n\nNote\n----\nThe nonlinear constitutive relation is solved iteratively; it may not converge\nfor strong nonlinearities. Increasing ``num_iters`` can help with convergence.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)\n>>> nonlinear_spec = NonlinearSpec(models=[nonlinear_susceptibility])\n>>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "models": { + "title": "Nonlinear models", + "description": "The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSusceptibility" + }, + { + "$ref": "#/definitions/TwoPhotonAbsorption" + }, + { + "$ref": "#/definitions/KerrNonlinearity" + } + ] + } + }, + "num_iters": { + "title": "Number of iterations", + "description": "Number of iterations for solving nonlinear constitutive relation.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "NonlinearSpec", + "enum": [ + "NonlinearSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SpaceModulation": { + "title": "SpaceModulation", + "description": "The modulation profile with a user-supplied spatial distribution of\namplitude and phase.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : Union[float, SpatialDataArray] = 1\n Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.\nphase : Union[float, SpatialDataArray] = 0\n [units = rad]. Phase of modulation that can vary spatially.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Method of interpolation to use to obtain values at spatial locations on the Yee grids.\n\nNote\n----\n.. math::\n\n amp\\_space(r) = amplitude(r) \\cdot e^{i \\cdot phase(r)}\n\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> amp = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> phase = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> space = SpaceModulation(amplitude=amp, phase=phase)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SpaceModulation", + "enum": [ + "SpaceModulation" + ], + "type": "string" + }, + "amplitude": { + "title": "Amplitude of modulation in space", + "description": "Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.", + "default": 1, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "phase": { + "title": "Phase of modulation in space", + "description": "Phase of modulation that can vary spatially.", + "default": 0, + "units": "rad", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Method of interpolation to use to obtain values at spatial locations on the Yee grids.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContinuousWaveTimeModulation": { + "title": "ContinuousWaveTimeModulation", + "description": "Class describing modulation with a harmonic time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Modulation frequency.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t}\n\nNote\n----\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\n\nExample\n-------\n>>> cw = ContinuousWaveTimeModulation(freq0=200e12, amplitude=1, phase=0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWaveTimeModulation", + "enum": [ + "ContinuousWaveTimeModulation" + ], + "type": "string" + }, + "freq0": { + "title": "Modulation Frequency", + "description": "Modulation frequency.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "freq0" + ], + "additionalProperties": false + }, + "SpaceTimeModulation": { + "title": "SpaceTimeModulation", + "description": "Space-time modulation applied to a medium, adding\non top of the time-independent part.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nspace_modulation : SpaceModulation = SpaceModulation(attrs={}, type='SpaceModulation', amplitude=1.0, phase=0.0, interp_method='nearest')\n Space modulation part from the separable SpaceTimeModulation.\ntime_modulation : ContinuousWaveTimeModulation\n Time modulation part from the separable SpaceTimeModulation.\n\n\nNote\n----\nThe space-time modulation must be separable in space and time.\ne.g. when applied to permittivity,\n\n.. math::\n\n \\delta \\epsilon(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "space_modulation": { + "title": "Space modulation", + "description": "Space modulation part from the separable SpaceTimeModulation.", + "default": { + "attrs": {}, + "type": "SpaceModulation", + "amplitude": 1.0, + "phase": 0.0, + "interp_method": "nearest" + }, + "allOf": [ + { + "$ref": "#/definitions/SpaceModulation" + } + ] + }, + "time_modulation": { + "title": "Time modulation", + "description": "Time modulation part from the separable SpaceTimeModulation.", + "allOf": [ + { + "$ref": "#/definitions/ContinuousWaveTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "SpaceTimeModulation", + "enum": [ + "SpaceTimeModulation" + ], + "type": "string" + } + }, + "required": [ + "time_modulation" + ], + "additionalProperties": false + }, + "ModulationSpec": { + "title": "ModulationSpec", + "description": "Specification adding space-time modulation to the non-dispersive part of medium\nincluding relative permittivity at infinite frequency and electric conductivity.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npermittivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.\nconductivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of electric conductivity applied on top of the base conductivity.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "permittivity": { + "title": "Space-time modulation of relative permittivity", + "description": "Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "conductivity": { + "title": "Space-time modulation of conductivity", + "description": "Space-time modulation of electric conductivity applied on top of the base conductivity.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "ModulationSpec", + "enum": [ + "ModulationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VisualizationSpec": { + "title": "VisualizationSpec", + "description": "Defines specification for visualization when used with plotting functions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfacecolor : str = \n Color applied to the faces in visualization.\nedgecolor : Optional[str] = \n Color applied to the edges in visualization.\nalpha : Optional[ConstrainedFloatValue] = 1.0\n Opacity/alpha value in plotting between 0 and 1.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "facecolor": { + "title": "Face color", + "description": "Color applied to the faces in visualization.", + "default": "", + "type": "string" + }, + "edgecolor": { + "title": "Edge color", + "description": "Color applied to the edges in visualization.", + "default": "", + "type": "string" + }, + "alpha": { + "title": "Opacity", + "description": "Opacity/alpha value in plotting between 0 and 1.", + "default": 1.0, + "minimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "VisualizationSpec", + "enum": [ + "VisualizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FluidSpec": { + "title": "FluidSpec", + "description": "Fluid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidSpec", + "enum": [ + "FluidSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SolidSpec": { + "title": "SolidSpec", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidSpec", + "enum": [ + "SolidSpec" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "SolidMedium": { + "title": "SolidMedium", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidMedium", + "enum": [ + "SolidMedium" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "FluidMedium": { + "title": "FluidMedium", + "description": "Fluid medium. Heat simulations will not solve for temperature\nin a structure that has a medium with this 'heat_spec'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\n\nExample\n-------\n>>> solid = FluidMedium()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidMedium", + "enum": [ + "FluidMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Medium": { + "title": "Medium", + "description": "Dispersionless medium. Mediums define the optical properties of the materials within the simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n In a dispersion-less medium, the displacement field :math:`D(t)` reacts instantaneously to the applied\n electric field :math:`E(t)`.\n\n .. math::\n\n D(t) = \\epsilon E(t)\n\nExample\n-------\n>>> dielectric = Medium(permittivity=4.0, name='my_medium')\n>>> eps = dielectric.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Introduction on Tidy3D working principles <../../notebooks/Primer.html#Mediums>`_\n * `Index <../../notebooks/docs/features/medium.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_\n\n**GUI**\n * `Mediums `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium", + "enum": [ + "Medium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "additionalProperties": false + }, + "HammerstadSurfaceRoughness": { + "title": "HammerstadSurfaceRoughness", + "description": "Modified Hammerstad surface roughness model. It's a popular model that works well\nunder 5 GHz for surface roughness below 2 micrometer RMS.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrq : PositiveFloat\n [units = um]. RMS peak-to-valley height (Rq) of the surface roughness.\nroughness_factor : ConstrainedFloatValue = 2.0\n Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n 1 + (RF-1) \\frac{2}{\\pi}\\arctan(1.4\\frac{R_q^2}{\\delta^2})\n\n where :math:`\\delta` is skin depth, :math:`R_q` the RMS peak-to-vally height, and RF\n roughness factor.\n\nNote\n----\nThis model is based on:\n\n Y. Shlepnev, C. Nwachukwu, \"Roughness characterization for interconnect analysis\",\n 2011 IEEE International Symposium on Electromagnetic Compatibility,\n (DOI: 10.1109/ISEMC.2011.6038367), 2011.\n\n V. Dmitriev-Zdorov, B. Simonovich, I. Kochikov, \"A Causal Conductor Roughness Model\n and its Effect on Transmission Line Characteristics\", Signal Integrity Journal, 2018.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HammerstadSurfaceRoughness", + "enum": [ + "HammerstadSurfaceRoughness" + ], + "type": "string" + }, + "rq": { + "title": "RMS Peak-to-Valley Height", + "description": "RMS peak-to-valley height (Rq) of the surface roughness.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "roughness_factor": { + "title": "Roughness Factor", + "description": "Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.", + "default": 2.0, + "exclusiveMinimum": 1.0, + "type": "number" + } + }, + "required": [ + "rq" + ], + "additionalProperties": false + }, + "HuraySurfaceRoughness": { + "title": "HuraySurfaceRoughness", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HuraySurfaceRoughness", + "enum": [ + "HuraySurfaceRoughness" + ], + "type": "string" + }, + "relative_area": { + "title": "Relative Area", + "description": "Relative area of the matte base compared to a flat surface", + "default": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients for surface ratio and sphere radius", + "description": "List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.", + "units": [ + null, + "um" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "SurfaceImpedanceFitterParam": { + "title": "SurfaceImpedanceFitterParam", + "description": "Advanced parameters for fitting surface impedance of a :class:`.LossyMetalMedium`.\nInternally, the quantity to be fitted is surface impedance divided by ``-1j * \\omega``.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_num_poles : PositiveInt = 5\n Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.\ntolerance_rms : NonNegativeFloat = 0.001\n Tolerance in fitting.\nfrequency_sampling_points : PositiveInt = 20\n Number of sampling frequencies used in fitting.\nlog_sampling : bool = True\n Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "max_num_poles": { + "title": "Maximal Number Of Poles", + "description": "Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "tolerance_rms": { + "title": "Tolerance In Fitting", + "description": "Tolerance in fitting.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "frequency_sampling_points": { + "title": "Number Of Sampling Frequencies", + "description": "Number of sampling frequencies used in fitting.", + "default": 20, + "exclusiveMinimum": 0, + "type": "integer" + }, + "log_sampling": { + "title": "Frequencies Sampling In Log Scale", + "description": "Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedanceFitterParam", + "enum": [ + "SurfaceImpedanceFitterParam" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LossyMetalMedium": { + "title": "LossyMetalMedium", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Frequency range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "LossyMetalMedium", + "enum": [ + "LossyMetalMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "enum": [ + 1 + ], + "type": "integer" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "roughness": { + "title": "Surface Roughness Model", + "description": "Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.", + "discriminator": { + "propertyName": "type", + "mapping": { + "HammerstadSurfaceRoughness": "#/definitions/HammerstadSurfaceRoughness", + "HuraySurfaceRoughness": "#/definitions/HuraySurfaceRoughness" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HammerstadSurfaceRoughness" + }, + { + "$ref": "#/definitions/HuraySurfaceRoughness" + } + ] + }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "fit_param": { + "title": "Fitting Parameters For Surface Impedance", + "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", + "default": { + "attrs": {}, + "max_num_poles": 5, + "tolerance_rms": 0.001, + "frequency_sampling_points": 20, + "log_sampling": true, + "type": "SurfaceImpedanceFitterParam" + }, + "allOf": [ + { + "$ref": "#/definitions/SurfaceImpedanceFitterParam" + } + ] + } + }, + "required": [ + "frequency_range" + ], + "additionalProperties": false + }, + "PoleResidue": { + "title": "PoleResidue", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PoleResidue", + "enum": [ + "PoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + } + }, + "additionalProperties": false + }, + "Sellmeier": { + "title": "Sellmeier", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Sellmeier", + "enum": [ + "Sellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Lorentz": { + "title": "Lorentz", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Lorentz", + "enum": [ + "Lorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number", + "minimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Debye": { + "title": "Debye", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Debye", + "enum": [ + "Debye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Drude": { + "title": "Drude", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Drude", + "enum": [ + "Drude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "PECMedium": { + "title": "PECMedium", + "description": "Perfect electrical conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PECs, must import ``tidy3d.PEC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PECMedium", + "enum": [ + "PECMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AnisotropicMedium": { + "title": "AnisotropicMedium", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMedium", + "enum": [ + "AnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "FullyAnisotropicMedium": { + "title": "FullyAnisotropicMedium", + "description": "Fully anisotropic medium including all 9 components of the permittivity and conductivity\ntensors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]\n [units = None (relative permittivity)]. Relative permittivity tensor.\nconductivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n [units = S/um]. Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n Provided permittivity tensor and the symmetric part of the conductivity tensor must\n have coinciding main directions. A non-symmetric conductivity tensor can be used to model\n magneto-optic effects. Note that dispersive properties and subpixel averaging are currently not\n supported for fully anisotropic materials.\n\nNote\n----\n\n Simulations involving fully anisotropic materials are computationally more intensive, thus,\n they take longer time to complete. This increase strongly depends on the filling fraction of\n the simulation domain by fully anisotropic materials, varying approximately in the range from\n 1.5 to 5. The cost of running a simulation is adjusted correspondingly.\n\nExample\n-------\n>>> perm = [[2, 0, 0], [0, 1, 0], [0, 0, 3]]\n>>> cond = [[0.1, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> anisotropic_dielectric = FullyAnisotropicMedium(permittivity=perm, conductivity=cond)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "FullyAnisotropicMedium", + "enum": [ + "FullyAnisotropicMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity tensor.", + "default": [ + [ + 1, + 0, + 0 + ], + [ + 0, + 1, + 0 + ], + [ + 0, + 0, + 1 + ] + ], + "units": "None (relative permittivity)", + "type": "ArrayLike" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "units": "S/um", + "type": "ArrayLike" + } + }, + "additionalProperties": false + }, + "PermittivityDataset": { + "title": "PermittivityDataset", + "description": "Dataset storing the diagonal components of the permittivity tensor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\neps_xx : ScalarFieldDataArray\n Spatial distribution of the xx-component of the relative permittivity.\neps_yy : ScalarFieldDataArray\n Spatial distribution of the yy-component of the relative permittivity.\neps_zz : ScalarFieldDataArray\n Spatial distribution of the zz-component of the relative permittivity.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> sclr_fld = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = PermittivityDataset(eps_xx=sclr_fld, eps_yy=sclr_fld, eps_zz=sclr_fld)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityDataset", + "enum": [ + "PermittivityDataset" + ], + "type": "string" + }, + "eps_xx": { + "title": "DataArray", + "description": "Spatial distribution of the xx-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_yy": { + "title": "DataArray", + "description": "Spatial distribution of the yy-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_zz": { + "title": "DataArray", + "description": "Spatial distribution of the zz-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "eps_xx", + "eps_yy", + "eps_zz" + ], + "additionalProperties": false + }, + "TriangularGridDataset": { + "title": "TriangularGridDataset", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangularGridDataset", + "enum": [ + "TriangularGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "normal_axis": { + "title": "Grid Axis", + "description": "Orientation of the grid.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "normal_pos": { + "title": "Position", + "description": "Coordinate of the grid along the normal direction.", + "type": "number" + } + }, + "required": [ + "points", + "values", + "cells", + "normal_axis", + "normal_pos" + ], + "additionalProperties": false + }, + "TetrahedralGridDataset": { + "title": "TetrahedralGridDataset", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TetrahedralGridDataset", + "enum": [ + "TetrahedralGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "points", + "values", + "cells" + ], + "additionalProperties": false + }, + "CustomMedium": { + "title": "CustomMedium", + "description": ":class:`.Medium` with user-supplied permittivity distribution.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\neps_dataset : Optional[PermittivityDataset] = None\n [To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.\npermittivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = None (relative permittivity)]. Spatial profile of relative permittivity.\nconductivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = S/um]. Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> dielectric = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> eps = dielectric.eps_model(200e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomMedium", + "enum": [ + "CustomMedium" + ], + "type": "string" + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + }, + "eps_dataset": { + "title": "Permittivity Dataset", + "description": "[To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.", + "allOf": [ + { + "$ref": "#/definitions/PermittivityDataset" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Spatial profile of relative permittivity.", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "units": "S/um", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + }, + "additionalProperties": false + }, + "CustomPoleResidue": { + "title": "CustomPoleResidue", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomPoleResidue", + "enum": [ + "CustomPoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf" + ], + "additionalProperties": false + }, + "CustomSellmeier": { + "title": "CustomSellmeier", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomSellmeier", + "enum": [ + "CustomSellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "CustomLorentz": { + "title": "CustomLorentz", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomLorentz", + "enum": [ + "CustomLorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDebye": { + "title": "CustomDebye", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDebye", + "enum": [ + "CustomDebye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDrude": { + "title": "CustomDrude", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDrude", + "enum": [ + "CustomDrude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomAnisotropicMedium": { + "title": "CustomAnisotropicMedium", + "description": "Diagonally anisotropic medium with spatially varying permittivity in each component.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\ninterp_method : Optional[Literal['nearest', 'linear']] = None\n When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.\nsubpixel : Optional[bool] = None\n This field is ignored. Please set ``subpixel`` in each component\n\nNote\n----\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> x = np.linspace(-1, 1, Nx)\n>>> y = np.linspace(-1, 1, Ny)\n>>> z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=x, y=y, z=z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> medium_xx = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> medium_yy = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> d_epsilon = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> medium_zz = CustomLorentz(eps_inf=permittivity, coeffs=[(d_epsilon,f,delta),])\n>>> anisotropic_dielectric = CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomAnisotropicMedium", + "enum": [ + "CustomAnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This field is ignored. Please set ``subpixel`` in each component", + "type": "boolean" + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "LinearHeatPerturbation": { + "title": "LinearHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a linear function of\ntemperature.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n [units = K]. Temperature range in which perturbation model is valid.\ntemperature_ref : NonNegativeFloat\n [units = K]. Temperature at which perturbation is zero.\ncoeff : Union[float, tidycomplex, ComplexNumber]\n [units = 1/K]. Sensitivity (derivative) of perturbation with respect to temperature.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{coeff} \\times (T - \\text{temperature\\_ref}),\n\n where ``coeff`` is the parameter's sensitivity (thermo-optic coefficient) to temperature and\n ``temperature_ref`` is the reference temperature point. A temperature range in which such\n a model is deemed accurate may be provided as a field ``temperature_range``\n (default: ``[0, inf]``). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.0001,\n... temperature_range=[200, 500],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearHeatPerturbation", + "enum": [ + "LinearHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "temperature_ref": { + "title": "Reference temperature", + "description": "Temperature at which perturbation is zero.", + "units": "K", + "minimum": 0, + "type": "number" + }, + "coeff": { + "title": "Thermo-optic Coefficient", + "description": "Sensitivity (derivative) of perturbation with respect to temperature.", + "units": "1/K", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "required": [ + "temperature_ref", + "coeff" + ], + "additionalProperties": false + }, + "CustomHeatPerturbation": { + "title": "CustomHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a custom function of\ntemperature defined as an array of perturbation values at sample temperature points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n [units = K]. Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.\nperturbation_values : HeatDataArray\n Sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\n Notes\n -----\n\n The linear\n interpolation is used to calculate perturbation values between sample temperature points. For\n temperature values outside of the provided sample region the perturbation value is extrapolated\n as a constant.\n The temperature range, ``temperature_range``, in which the perturbation model is assumed to be\n accurate is calculated automatically as the minimal and maximal sample temperature points.\n Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> from tidy3d import HeatDataArray\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomHeatPerturbation", + "enum": [ + "CustomHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.", + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "Sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "LinearChargePerturbation": { + "title": "LinearChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a linear function of\nelectron and hole densities:\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of electrons densities in which perturbation model is valid.\nhole_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of holes densities in which perturbation model is valid.\nelectron_ref : NonNegativeFloat\n [units = 1/cm^3]. Electron density value at which there is no perturbation due to electrons's presence.\nhole_ref : NonNegativeFloat\n [units = 1/cm^3]. Hole density value at which there is no perturbation due to holes' presence.\nelectron_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to electron density.\nhole_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to hole density.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{electron\\_coeff} \\times (N_e - \\text{electron\\_ref})\n + \\text{hole\\_coeff} \\times (N_h - \\text{hole\\_ref}),\n\n where ``electron_coeff`` and ``hole_coeff`` are the parameter's sensitivities to electron and\n hole densities, while ``electron_ref`` and ``hole_ref`` are reference electron and hole density\n values. Ranges of electron and hole densities in which such\n a model is deemed accurate may be provided as fields ``electron_range`` and ``hole_range``\n (default: ``[0, inf]`` each). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``electron_range`` x ``hole_range`` due to\n perturbations and raise a warning if this check fails. A warning is also issued if\n the perturbation model is evaluated outside of ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearChargePerturbation", + "enum": [ + "LinearChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "electron_ref": { + "title": "Reference Electron Density", + "description": "Electron density value at which there is no perturbation due to electrons's presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "hole_ref": { + "title": "Reference Hole Density", + "description": "Hole density value at which there is no perturbation due to holes' presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "electron_coeff": { + "title": "Sensitivity to Electron Density", + "description": "Sensitivity (derivative) of perturbation with respect to electron density.", + "units": "cm^3", + "type": "number" + }, + "hole_coeff": { + "title": "Sensitivity to Hole Density", + "description": "Sensitivity (derivative) of perturbation with respect to hole density.", + "units": "cm^3", + "type": "number" + } + }, + "required": [ + "electron_ref", + "hole_ref", + "electron_coeff", + "hole_coeff" + ], + "additionalProperties": false + }, + "CustomChargePerturbation": { + "title": "CustomChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a custom function of\nelectron and hole densities defined as a two-dimensional array of perturbation values at sample\nelectron and hole density points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nhole_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nperturbation_values : ChargeDataArray\n 2D array (vs electron and hole densities) of sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\nNotes\n-----\n\n The linear interpolation is used to calculate perturbation\n values between sample points. For electron and hole density values outside of the provided\n sample region the perturbation value is extrapolated as a constant.\n The electron and hole density ranges, ``electron_range`` and ``hole_range``, in which\n the perturbation model is assumed to be accurate is calculated automatically as the minimal and\n maximal density values provided in ``perturbation_values``. Wherever is applied, Tidy3D will\n check that the parameter's value does not go out of its physical bounds within\n ``electron_range`` x ``hole_range`` due to perturbations and raise a warning if this check\n fails. A warning is also issued if the perturbation model is evaluated outside of\n ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> from tidy3d import ChargeDataArray\n>>> perturbation_data = ChargeDataArray(\n... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],\n... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),\n... )\n>>> charge_perturb = CustomChargePerturbation(\n... perturbation_values=perturbation_data,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomChargePerturbation", + "enum": [ + "CustomChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "2D array (vs electron and hole densities) of sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "ParameterPerturbation": { + "title": "ParameterPerturbation", + "description": "Stores information about parameter perturbations due to different physical effect. If both\nheat and charge perturbation models are included their effects are superimposed.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nheat : Union[LinearHeatPerturbation, CustomHeatPerturbation] = None\n Heat perturbation to apply.\ncharge : Union[LinearChargePerturbation, CustomChargePerturbation] = None\n Charge perturbation to apply.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, CustomHeatPerturbation, HeatDataArray\n>>>\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )\n>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "heat": { + "title": "Heat Perturbation", + "description": "Heat perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearHeatPerturbation": "#/definitions/LinearHeatPerturbation", + "CustomHeatPerturbation": "#/definitions/CustomHeatPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearHeatPerturbation" + }, + { + "$ref": "#/definitions/CustomHeatPerturbation" + } + ] + }, + "charge": { + "title": "Charge Perturbation", + "description": "Charge perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearChargePerturbation": "#/definitions/LinearChargePerturbation", + "CustomChargePerturbation": "#/definitions/CustomChargePerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearChargePerturbation" + }, + { + "$ref": "#/definitions/CustomChargePerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "ParameterPerturbation", + "enum": [ + "ParameterPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityPerturbation": { + "title": "PermittivityPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\npermittivity and conductivity.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_eps : Optional[ParameterPerturbation] = None\n Perturbation model for permittivity.\ndelta_sigma : Optional[ParameterPerturbation] = None\n Perturbation model for conductivity.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, PermittivityPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> delta_eps = ParameterPerturbation(heat=heat_perturb)\n>>> delta_sigma = ParameterPerturbation(charge=charge_perturb)\n>>> permittivity_pb = PermittivityPerturbation(delta_eps=delta_eps, delta_sigma=delta_sigma)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_eps": { + "title": "Permittivity Perturbation", + "description": "Perturbation model for permittivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_sigma": { + "title": "Conductivity Perturbation", + "description": "Perturbation model for conductivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PermittivityPerturbation", + "enum": [ + "PermittivityPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IndexPerturbation": { + "title": "IndexPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\nrefractive index, n and k.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_n : Optional[ParameterPerturbation] = None\n Perturbation of the real part of refractive index.\ndelta_k : Optional[ParameterPerturbation] = None\n Perturbation of the imaginary part of refractive index.\nfreq : NonNegativeFloat\n [units = Hz]. Frequency to evaluate permittivity at (Hz).\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, IndexPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> dn_pb = ParameterPerturbation(heat=heat_perturb)\n>>> dk_pb = ParameterPerturbation(charge=charge_perturb)\n>>> index_pb = IndexPerturbation(delta_n=dn_pb, delta_k=dk_pb, freq=C_0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_n": { + "title": "Refractive Index Perturbation", + "description": "Perturbation of the real part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_k": { + "title": "Exctinction Coefficient Perturbation", + "description": "Perturbation of the imaginary part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "freq": { + "title": "Frequency", + "description": "Frequency to evaluate permittivity at (Hz).", + "units": "Hz", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "IndexPerturbation", + "enum": [ + "IndexPerturbation" + ], + "type": "string" + } + }, + "required": [ + "freq" + ], + "additionalProperties": false + }, + "PerturbationMedium": { + "title": "PerturbationMedium", + "description": "Dispersionless medium with perturbations. Perturbation model can be defined either directly\nthrough providing ``permittivity_perturbation`` and ``conductivity_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\npermittivity_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. List of heat and/or charge perturbations to permittivity.\nconductivity_perturbation : Optional[ParameterPerturbation] = None\n [units = S/um]. List of heat and/or charge perturbations to permittivity.\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> dielectric = PerturbationMedium(\n... permittivity=4.0,\n... permittivity_perturbation=ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... ),\n... name='my_medium',\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationMedium", + "enum": [ + "PerturbationMedium" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "permittivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "conductivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "S/um", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + }, + "additionalProperties": false + }, + "PerturbationPoleResidue": { + "title": "PerturbationPoleResidue", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationPoleResidue", + "enum": [ + "PerturbationPoleResidue" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + }, + "eps_inf_perturbation": { + "title": "Perturbation of Epsilon at Infinity", + "description": "Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "poles_perturbation": { + "title": "Perturbations of Poles", + "description": "Perturbations to poles of the model.", + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "$ref": "#/definitions/ParameterPerturbation" + }, + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + } + }, + "additionalProperties": false + }, + "Box": { + "title": "Box", + "description": "Rectangular prism.\n Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\n\nExample\n-------\n>>> b = Box(center=(1,2,3), size=(2,2,2))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Box", + "enum": [ + "Box" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "Sphere": { + "title": "Sphere", + "description": "Spherical geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nradius : NonNegativeFloat\n [units = um]. Radius of geometry.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\n\nExample\n-------\n>>> b = Sphere(center=(1,2,3), radius=2)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Sphere", + "enum": [ + "Sphere" + ], + "type": "string" + }, + "radius": { + "title": "Radius", + "description": "Radius of geometry.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "radius" + ], + "additionalProperties": false + }, + "Cylinder": { + "title": "Cylinder", + "description": "Cylindrical geometry with optional sidewall angle along axis\ndirection. When ``sidewall_angle`` is nonzero, the shape is a\nconical frustum or a cone.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> c = Cylinder(center=(1,2,3), radius=2, length=5, axis=2)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../../notebooks/THzDemultiplexerFilter.html>`_\n* `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Cylinder", + "enum": [ + "Cylinder" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([(0,0), (1,0), (1,1)])\n>>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolySlab", + "enum": [ + "PolySlab" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])\n>>> faces = np.array([[1, 2, 3], [0, 3, 2], [0, 1, 3], [0, 2, 1]])\n>>> stl_geom = TriangleMesh.from_vertices_faces(vertices, faces)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangleMesh", + "enum": [ + "TriangleMesh" + ], + "type": "string" + }, + "mesh_dataset": { + "title": "Surface mesh data", + "description": "Surface mesh data.", + "allOf": [ + { + "$ref": "#/definitions/TriangleMeshDataset" + } + ] + } + }, + "required": [ + "mesh_dataset" + ], + "additionalProperties": false + }, + "GeometryGroup": { + "title": "GeometryGroup", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GeometryGroup", + "enum": [ + "GeometryGroup" + ], + "type": "string" + }, + "geometries": { + "title": "Geometries", + "description": "Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + } + }, + "required": [ + "geometries" + ], + "additionalProperties": false + }, + "ClipOperation": { + "title": "ClipOperation", + "description": "Class representing the result of a set operation between geometries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\noperation : Literal['union', 'intersection', 'difference', 'symmetric_difference']\n Operation to be performed between geometries.\ngeometry_a : ForwardRef('annotate_type(GeometryType)')\n First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.\ngeometry_b : ForwardRef('annotate_type(GeometryType)')\n Second operand for the set operation. It can also be any geometry type.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ClipOperation", + "enum": [ + "ClipOperation" + ], + "type": "string" + }, + "operation": { + "title": "Operation Type", + "description": "Operation to be performed between geometries.", + "enum": [ + "union", + "intersection", + "difference", + "symmetric_difference" + ], + "type": "string" + }, + "geometry_a": { + "title": "Geometry A", + "description": "First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "geometry_b": { + "title": "Geometry B", + "description": "Second operand for the set operation. It can also be any geometry type.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + }, + "required": [ + "operation", + "geometry_a", + "geometry_b" + ], + "additionalProperties": false + }, + "Transformed": { + "title": "Transformed", + "description": "Class representing a transformed geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : ForwardRef('annotate_type(GeometryType)')\n Base geometry to be transformed.\ntransform : ArrayLike[dtype=float, ndim=2, shape=(4, 4)] = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]\n Transform matrix applied to the base geometry.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Transformed", + "enum": [ + "Transformed" + ], + "type": "string" + }, + "geometry": { + "title": "Geometry", + "description": "Base geometry to be transformed.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "transform": { + "title": "Transform", + "description": "Transform matrix applied to the base geometry.", + "default": [ + [ + 1.0, + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "type": "ArrayLike" + } + }, + "required": [ + "geometry" + ], + "additionalProperties": false + }, + "Medium2D": { + "title": "Medium2D", + "description": "2D diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nss : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.\ntt : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> medium2d = Medium2D(ss=drude_medium, tt=drude_medium)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium2D", + "enum": [ + "Medium2D" + ], + "type": "string" + }, + "ss": { + "title": "SS Component", + "description": "Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + }, + "tt": { + "title": "TT Component", + "description": "Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + } + }, + "required": [ + "ss", + "tt" + ], + "additionalProperties": false + }, + "AnisotropicMediumFromMedium2D": { + "title": "AnisotropicMediumFromMedium2D", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMediumFromMedium2D", + "enum": [ + "AnisotropicMediumFromMedium2D" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "ChargeConductorMedium": { + "title": "ChargeConductorMedium", + "description": "Conductor medium for conduction simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : PositiveFloat\n [units = S/um]. Electric conductivity of material in units of S/um.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeConductorMedium(conductivity=3)\n\nNote\n----\n A relative permittivity will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeConductorMedium", + "enum": [ + "ChargeConductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "conductivity": { + "title": "Electric conductivity", + "description": "Electric conductivity of material in units of S/um.", + "units": "S/um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "ChargeInsulatorMedium": { + "title": "ChargeInsulatorMedium", + "description": "Insulating medium. Conduction simulations will not solve for electric\npotential in a structure that has a medium with this 'charge'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeInsulatorMedium()\n>>> solid2 = td.ChargeInsulatorMedium(permittivity=1.1)\n\nNote\n----\n A relative permittivity :math:`\\varepsilon` will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeInsulatorMedium", + "enum": [ + "ChargeInsulatorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + } + }, + "additionalProperties": false + }, + "CaugheyThomasMobility": { + "title": "CaugheyThomasMobility", + "description": "The Caughey-Thomas temperature-dependent carrier mobility model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu_min : PositiveFloat\n Minimum electron mobility at reference temperature (300K) in cm^2/V-s. \nmu : PositiveFloat\n Reference mobility at reference temperature (300K) in cm^2/V-s\nexp_2 : float\n exp_N : PositiveFloat\n Exponent for doping dependence of mobility at reference temperature (300K).\nref_N : PositiveFloat\n Reference doping at reference temperature (300K) in #/cm^3.\nexp_1 : float\n Exponent of thermal dependence of minimum mobility.\nexp_3 : float\n Exponent of thermal dependence of reference doping.\nexp_4 : float\n Exponent of thermal dependence of the doping exponent effect.\n\nNotes\n-----\n The general form of the Caughey-Thomas mobility model [1]_ is of the form:\n\n .. math::\n\n \\mu_0 = \\frac{\\mu_{max} - \\mu_{min}}{1 + \\left(N/N_{ref}\\right)^z} + \\mu_{min}\n\nwhere :math:`\\mu_0` represents the low-field mobility and :math:`N` is the total doping (acceptors + donors).\n:math:`\\mu_{max}`, :math:`\\mu_{min}`, :math:`z`, and :math:`N_{ref}` are temperature dependent,\nthe dependence being of the form\n\n.. math::\n\n \\phi = \\phi_{ref} \\left( \\frac{T}{T_{ref}}\\right)^\\alpha\n\nand :math:`T_{ref}` is taken to be 300K.\n\nThe complete form (with temperature effects) for the low-field mobility can be written as\n\n.. math::\n\n \\mu_0 = \\frac{\\mu_{max}(\\frac{T}{T_{ref}})^{\\alpha_2} - \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}}{1 + \\left(N/N_{ref}(\\frac{T}{T_{ref}})^{\\alpha_3}\\right)^{\\alpha_N(\\frac{T}{T_{ref}})^{\\alpha_4}}} + \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}\n\nThe following table maps the symbols used in the equations above with the names used in the code:\n\n.. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`\\mu_{min}`\n - ``mu_min``\n - Minimum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\mu_{max}`\n - ``mu_n``\n - Maximum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\alpha_1`\n - ``exp_1``\n - Exponent for temperature dependence of the minimum mobility coefficient\n * - :math:`\\alpha_2`\n - ``exp_2``\n - Exponent for temperature dependence of the maximum mobility coefficient\n * - :math:`\\alpha_N`\n - ``exp_N``\n - Exponent for doping dependence.\n * - :math:`\\alpha_4`\n - ``exp_4``\n - Exponent for the temperature dependence of the exponent :math:`\\alpha_N`\n * - :math:`N_{ref}`\n - ``ref_N``,\n - Reference doping parameter\n\n\n.. [1] M. Caughey and R.E. Thomas. Carrier mobilities in silicon empirically related to doping\n and field. Proceedings of the IEEE, 55(12):2192\u20132193, December 1967\n\nExample\n-------\n >>> import tidy3d as td\n >>> mobility_Si_n = td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n >>> mobility_Si_p = td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n\n\nWarning\n-------\nThere are some current limitations of this model:\n\n- High electric field effects not yet supported.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu_min": { + "title": "$\\mu_{min}$ Minimum electron mobility", + "description": "Minimum electron mobility at reference temperature (300K) in cm^2/V-s. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "mu": { + "title": "Reference mobility", + "description": "Reference mobility at reference temperature (300K) in cm^2/V-s", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_2": { + "title": "Exponent for temperature dependent behavior of reference mobility", + "type": "number" + }, + "exp_N": { + "title": "Exponent for doping dependence of mobility.", + "description": "Exponent for doping dependence of mobility at reference temperature (300K).", + "exclusiveMinimum": 0, + "type": "number" + }, + "ref_N": { + "title": "Reference doping", + "description": "Reference doping at reference temperature (300K) in #/cm^3.", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_1": { + "title": "Exponent of thermal dependence of minimum mobility.", + "description": "Exponent of thermal dependence of minimum mobility.", + "type": "number" + }, + "exp_3": { + "title": "Exponent of thermal dependence of reference doping.", + "description": "Exponent of thermal dependence of reference doping.", + "type": "number" + }, + "exp_4": { + "title": "Exponent of thermal dependence of the doping exponent effect.", + "description": "Exponent of thermal dependence of the doping exponent effect.", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CaugheyThomasMobility", + "enum": [ + "CaugheyThomasMobility" + ], + "type": "string" + } + }, + "required": [ + "mu_min", + "mu", + "exp_2", + "exp_N", + "ref_N", + "exp_1", + "exp_3", + "exp_4" + ], + "additionalProperties": false + }, + "ConstantMobilityModel": { + "title": "ConstantMobilityModel", + "description": "Constant mobility model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu : NonNegativeFloat\n [units = cm\u00b2/V-s]. Mobility\n\nExample\n-------\n>>> import tidy3d as td\n>>> mobility_model = td.ConstantMobilityModel(mu=1500)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu": { + "title": "Mobility", + "description": "Mobility", + "units": "cm\u00b2/V-s", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ConstantMobilityModel", + "enum": [ + "ConstantMobilityModel" + ], + "type": "string" + } + }, + "required": [ + "mu" + ], + "additionalProperties": false + }, + "AugerRecombination": { + "title": "AugerRecombination", + "description": "Parameters for the Auger recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nc_n : PositiveFloat\n Constant for electrons in cm^6/s\nc_p : PositiveFloat\n Constant for holes in cm^6/s\n\nNotes\n-----\n\n The Auger recombination rate ``R_A`` is primarily defined by the electrons and holes Auger recombination\n coefficients, :math:`C_n` and :math:`C_p`, respectively.\n\n .. math::\n\n R_A = \\left( C_n n + C_p p \\right) \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32,\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "c_n": { + "title": "Constant for electrons", + "description": "Constant for electrons in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "c_p": { + "title": "Constant for holes", + "description": "Constant for holes in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AugerRecombination", + "enum": [ + "AugerRecombination" + ], + "type": "string" + } + }, + "required": [ + "c_n", + "c_p" + ], + "additionalProperties": false + }, + "RadiativeRecombination": { + "title": "RadiativeRecombination", + "description": "Defines the parameters for the radiative recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr_const : float\n Radiation constant in cm^3/s\n\nNotes\n-----\n\n This is a direct recombination model primarily defined by a radiative recombination coefficient :math:`R_{\\text{rad}}`.\n\n .. math::\n\n R_{\\text{rad}} = C \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r_const": { + "title": "Radiation constant in cm^3/s", + "description": "Radiation constant in cm^3/s", + "type": "number" + }, + "type": { + "title": "Type", + "default": "RadiativeRecombination", + "enum": [ + "RadiativeRecombination" + ], + "type": "string" + } + }, + "required": [ + "r_const" + ], + "additionalProperties": false + }, + "FossumCarrierLifetime": { + "title": "FossumCarrierLifetime", + "description": "Parameters for the Fossum carrier lifetime model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_300 : PositiveFloat\n [units = sec]. Carrier lifetime at 300K\nalpha_T : float\n Exponent for thermal dependence\nN0 : PositiveFloat\n [units = 1/cm^3]. Reference concentration\nA : float\n Constant A\nB : float\n Constant B\nC : float\n Constant C\nalpha : float\n Exponent constant\n\nNotes\n-----\n\n This model expresses the carrier lifetime as a function of the temperature and doping concentration.\n\n .. math::\n\n \\tau = \\frac{\\tau_{300} \\left( T/300 \\right)^\\alpha_T}{A + B (N/N_0) + C (N/N_0)^\\alpha}\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.FossumCarrierLifetime(\n ... tau_300=3.3e-6,\n ... alpha_T=-0.5,\n ... N0=7.1e15,\n ... A=1,\n ... B=0,\n ... C=1,\n ... alpha=1\n ... )\n\nReferences\n----------\n\n Fossum, J. G., and D. S. Lee. \"A physical model for the dependence of carrier lifetime on doping density in nondegenerate silicon.\" Solid-State Electronics 25.8 (1982): 741-747.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_300": { + "title": "Tau at 300K", + "description": "Carrier lifetime at 300K", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "alpha_T": { + "title": "Exponent for thermal dependence", + "description": "Exponent for thermal dependence", + "type": "number" + }, + "N0": { + "title": "Reference concentration", + "description": "Reference concentration", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "A": { + "title": "Constant A", + "description": "Constant A", + "type": "number" + }, + "B": { + "title": "Constant B", + "description": "Constant B", + "type": "number" + }, + "C": { + "title": "Constant C", + "description": "Constant C", + "type": "number" + }, + "alpha": { + "title": "Exponent constant", + "description": "Exponent constant", + "type": "number" + }, + "type": { + "title": "Type", + "default": "FossumCarrierLifetime", + "enum": [ + "FossumCarrierLifetime" + ], + "type": "string" + } + }, + "required": [ + "tau_300", + "alpha_T", + "N0", + "A", + "B", + "C", + "alpha" + ], + "additionalProperties": false + }, + "ShockleyReedHallRecombination": { + "title": "ShockleyReedHallRecombination", + "description": "Defines the parameters for the Shockley-Reed-Hall (SRH) recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_n : Union[PositiveFloat, FossumCarrierLifetime]\n Electron lifetime\ntau_p : Union[PositiveFloat, FossumCarrierLifetime]\n [units = sec]. Hole lifetime\n\nNotes\n-----\n\n The recombination rate parameter from this model is defined from [1]_ as follows:\n\n .. math::\n\n R_{SRH} = \\frac{n p - n_0 p_0}{\\tau_p \\left(n + \\sqrt{n_0 p_0}\\right) + \\tau_n \\left(p + \\sqrt{n_0 p_0}\\right)}.\n\n Note that the electron and holes densities are defined within the :class:`SemiconductorMedium`. The electron\n lifetime :math:`\\tau_n` and hole lifetimes :math:`\\tau_p` need to be defined.\n\n\n .. [1] Schenk. A model for the field and temperature dependence of shockley-read-hall\n lifetimes in silicon. Solid-State Electronics, 35:1585\u20131596, 1992.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6,\n ... )\n\nNote\n----\nImportant considerations when using this model:\n\n- Currently, lifetimes are considered constant (not dependent on temperature or doping).\n- This model represents mid-gap traps Shockley-Reed-Hall recombination.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_n": { + "title": "Electron lifetime", + "description": "Electron lifetime", + "union": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "tau_p": { + "title": "Hole lifetime", + "description": "Hole lifetime", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "type": { + "title": "Type", + "default": "ShockleyReedHallRecombination", + "enum": [ + "ShockleyReedHallRecombination" + ], + "type": "string" + } + }, + "required": [ + "tau_n", + "tau_p" + ], + "additionalProperties": false + }, + "SlotboomBandGapNarrowing": { + "title": "SlotboomBandGapNarrowing", + "description": "Parameters for the Slotboom model for band-gap narrowing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nv1 : PositiveFloat\n [units = V]. $V_{1,bgn}$ parameter\nn2 : PositiveFloat\n [units = 1/cm^3]. $N_{2,bgn}$ parameter\nc2 : float\n $C_{2,bgn}$ parameter\nmin_N : NonNegativeFloat\n [units = 1/cm^3]. Bandgap narrowing is applied at location where total doping is higher than 'min_N'.\n\nNotes\n------\n The Slotboom band-gap narrowing :math:`\\Delta E_G` model is discussed in [1]_ as follows:\n\n .. math::\n\n \\Delta E_G = V_{1,bgn} \\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right)\n + \\sqrt{\\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right) \\right)^2 + C_{2,bgn}} \\right)\n \\quad \\text{if} \\quad N_{tot} \\geq 10^{15} \\text{cm}^{-3},\n\n \\Delta E_G = 0 \\quad \\text{if} \\quad N_{tot} < 10^{15} \\text{cm}^{-3}.\n\n Note that :math:`N_{tot}` is the total doping as defined within a :class:`SemiconductorMedium`.\n\n Example\n -------\n >>> import tidy3d as td\n >>> default_Si = td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... )\n\n .. [1] 'UNIFIED APPARENT BANDGAP NARROWING IN n- AND p-TYPE SILICON' Solid-State Electronics Vol. 35, No. 2, pp. 125-129, 1992", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "v1": { + "title": "$V_{1,bgn}$ parameter", + "description": "$V_{1,bgn}$ parameter", + "units": "V", + "exclusiveMinimum": 0, + "type": "number" + }, + "n2": { + "title": "$N_{2,bgn}$ parameter", + "description": "$N_{2,bgn}$ parameter", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "c2": { + "title": "$C_{2,bgn}$ parameter", + "description": "$C_{2,bgn}$ parameter", + "type": "number" + }, + "min_N": { + "title": "Minimum total doping", + "description": "Bandgap narrowing is applied at location where total doping is higher than 'min_N'.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "SlotboomBandGapNarrowing", + "enum": [ + "SlotboomBandGapNarrowing" + ], + "type": "string" + } + }, + "required": [ + "v1", + "n2", + "c2", + "min_N" + ], + "additionalProperties": false + }, + "ConstantDoping": { + "title": "ConstantDoping", + "description": "Sets constant doping :math:`N` in the specified box with a :parameter`size` and :parameter:`concentration`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nconcentration : NonNegativeFloat = 0\n [units = 1/cm^3]. Doping concentration density in #/cm^3.\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> constant_box1 = td.ConstantDoping(center=(0, 0, 0), size=(2, 2, 2), concentration=1e18)\n>>> constant_box2 = td.ConstantDoping.from_bounds(rmin=box_coords[0], rmax=box_coords[1], concentration=1e18)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConstantDoping", + "enum": [ + "ConstantDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "concentration": { + "title": "Doping concentration density.", + "description": "Doping concentration density in #/cm^3.", + "default": 0, + "units": "1/cm^3", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "GaussianDoping": { + "title": "GaussianDoping", + "description": "Sets a gaussian doping in the specified box.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nref_con : PositiveFloat\n Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.\nconcentration : PositiveFloat\n The concentration at the center of the box.\nwidth : PositiveFloat\n Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. \nsource : str = xmin\n Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nNotes\n-----\nThe Gaussian doping concentration :math:`N` is defined in the following manner:\n\n- :math:`N=N_{\\text{max}}` at locations more than :math:``width`` um away from the sides of the box.\n- :math:`N=N_{\\text{ref}}` at location on the box sides.\n- a Gaussian variation between :math:`N_{\\text{max}}` and :math:`N_{\\text{ref}}` at locations less than ``width``\num away from the sides.\n\nBy definition, all sides of the box will have concentration :math:`N_{\\text{ref}}` (except the side specified\nas source) and the center of the box (``width`` away from the box sides) will have a concentration\n:math:`N_{\\text{max}}`.\n\n.. math::\n\n N = \\{N_{\\text{max}}\\} \\exp \\left[\n - \\ln \\left( \\frac{\\{N_{\\text{max}}\\}}{\\{N_{\\text{ref}}\\}} \\right)\n \\left( \\frac{(x|y|z) - \\{(x|y|z)_{\\text{box}}\\}}{\\text{width}} \\right)^2\n \\right]\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> gaussian_box1 = td.GaussianDoping(\n... center=(0, 0, 0),\n... size=(2, 2, 2),\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )\n>>> gaussian_box2 = td.GaussianDoping.from_bounds(\n... rmin=box_coords[0],\n... rmax=box_coords[1],\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GaussianDoping", + "enum": [ + "GaussianDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "ref_con": { + "title": "Reference concentration.", + "description": "Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concentration": { + "title": "Concentration", + "description": "The concentration at the center of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "width": { + "title": "Width of the gaussian.", + "description": "Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "source": { + "title": "Source face", + "description": "Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']", + "default": "xmin", + "type": "string" + } + }, + "required": [ + "size", + "ref_con", + "concentration", + "width" + ], + "additionalProperties": false + }, + "SemiconductorMedium": { + "title": "SemiconductorMedium", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "SemiconductorMedium", + "enum": [ + "SemiconductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "N_c": { + "title": "Effective density of electron states", + "description": "$N_c$ Effective density of states in the conduction band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "N_v": { + "title": "Effective density of hole states", + "description": "$N_v$ Effective density of states in the valence band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "E_g": { + "title": "Band-gap energy", + "description": "Band-gap energy", + "units": "eV", + "exclusiveMinimum": 0, + "type": "number" + }, + "mobility_n": { + "title": "Mobility model for electrons", + "description": "Mobility model for electrons", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "mobility_p": { + "title": "Mobility model for holes", + "description": "Mobility model for holes", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "R": { + "title": "Generation-Recombination models", + "description": "Array containing the R models to be applied to the material.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/AugerRecombination" + }, + { + "$ref": "#/definitions/RadiativeRecombination" + }, + { + "$ref": "#/definitions/ShockleyReedHallRecombination" + } + ] + } + }, + "delta_E_g": { + "title": "$\\Delta E_g$ Bandgap narrowing model.", + "description": "Bandgap narrowing model.", + "allOf": [ + { + "$ref": "#/definitions/SlotboomBandGapNarrowing" + } + ] + }, + "N_a": { + "title": "Doping: Acceptor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + }, + "N_d": { + "title": "Doping: Donor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + } + }, + "required": [ + "N_c", + "N_v", + "E_g", + "mobility_n", + "mobility_p" + ], + "additionalProperties": false + }, + "MultiPhysicsMedium": { + "title": "MultiPhysicsMedium", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Medium name", + "type": "string" + }, + "optical": { + "title": "Optical properties", + "description": "Specifies optical properties.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "heat": { + "title": "Heat properties", + "description": "Specifies properties for Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "charge": { + "title": "Charge properties", + "description": "Specifies properties for Charge simulations.", + "anyOf": [ + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "MultiPhysicsMedium", + "enum": [ + "MultiPhysicsMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Structure": { + "title": "Structure", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, + "type": { + "title": "Type", + "default": "Structure", + "enum": [ + "Structure" + ], + "type": "string" + }, + "medium": { + "title": "Medium", + "description": "Defines the electromagnetic properties of the structure's medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + } + }, + "required": [ + "geometry", + "medium" + ], + "additionalProperties": false + }, + "Periodic": { + "title": "Periodic", + "description": "Periodic boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Periodic", + "enum": [ + "Periodic" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECBoundary": { + "title": "PECBoundary", + "description": "Perfect electric conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PECBoundary", + "enum": [ + "PECBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCBoundary": { + "title": "PMCBoundary", + "description": "Perfect magnetic conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PMCBoundary", + "enum": [ + "PMCBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMLParams": { + "title": "PMLParams", + "description": "Specifies full set of parameters needed for complex, frequency-shifted PML.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\nkappa_order : NonNegativeInt = 3\n Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).\nkappa_min : NonNegativeFloat = 0.0\n \nkappa_max : NonNegativeFloat = 1.5\n \nalpha_order : NonNegativeInt = 3\n Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).\nalpha_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the PML alpha.\nalpha_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the PML alpha.\n\nExample\n-------\n>>> params = PMLParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5, kappa_min=0.0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "PMLParams", + "enum": [ + "PMLParams" + ], + "type": "string" + }, + "kappa_order": { + "title": "Kappa Order", + "description": "Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "kappa_min": { + "title": "Kappa Minimum", + "default": 0.0, + "minimum": 0, + "type": "number" + }, + "kappa_max": { + "title": "Kappa Maximum", + "default": 1.5, + "minimum": 0, + "type": "number" + }, + "alpha_order": { + "title": "Alpha Order", + "description": "Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "alpha_min": { + "title": "Alpha Minimum", + "description": "Minimum value of the PML alpha.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "alpha_max": { + "title": "Alpha Maximum", + "description": "Maximum value of the PML alpha.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "PML": { + "title": "PML", + "description": "Specifies a standard PML along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 12\n Number of layers of standard PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.5, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=3.0, alpha_order=1, alpha_min=0.0, alpha_max=0.0)\n Parameters of the complex frequency-shifted absorption poles.\n\nNotes\n------\n\n **1D Model Illustration**\n\n Consider a transformed wave equation in the :math:`x` dimension below _`[1]`:\n\n .. math::\n\n \\left( \\left( \\frac{1}{s(x)} \\frac{\\delta}{\\delta x} \\right)^2 - \\frac{1}{c^2} \\frac{\\delta^2}{\\delta t^2} \\right) E = 0\n\n where the wave stretch factor :math:`s(x)` depends on the PML boundary position in the :math:`x` dimension.\n\n .. TODO what is x at 0?\n\n .. math::\n\n s(x) = \\left \\{\n \\begin{array}{lr}\n 1, & \\text{for } x < 0 \\\\\n 1 - \\frac{\\sigma}{i \\omega \\epsilon_0}, & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n The wave equation can be solved and plotted accordingly as a function of the :math:`x` dimension.\n\n .. math::\n\n E(x) = \\left \\{\n \\begin{array}{lr}\n e^{i(kx - \\omega t)}, & \\text{for } x < 0 \\\\\n e^{i(kx - \\omega t)} \\times e^{-\\frac{\\sigma x}{c \\epsilon_0}} & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n Hence, we see how this PML stretch factor induces frequency-independent exponential attentation and no\n reflection after the boundary at :math:`x=0`.\n\n .. image:: ../../_static/img/pml_boundary.png\n\n .. TODO make this image better\n\n **Usage Caveats**\n\n A perfectly matched layer (PML) is the most commonly used boundary condition in FDTD simulations to truncate\n a simulation domain and absorb outgoing radiation. However, many divergence issues are associated with the\n use of PML. One of the most common causes of a diverged simulation is structures inserted into PML at an angle.\n\n .. TODO links to absorber boundaries\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation.png\n\n Incorporating a dispersive material into the PML can also cause simulation divergence in certain scenarios.\n If your simulation lacks any structures inserted into the PML at an angle, but includes dispersive material\n in PML, it is advisable to substitute a nondispersive material for the dispersive material. Alternatively,\n if dispersion is necessary, switching from the :class:`PML` to :class:`Absorber` can effectively address the\n issue.\n\n The PML can effectively absorb outgoing radiation with minimum reflection as if the radiation just propagates\n into the free space. However, it\u2019s important to keep in mind that the PML only absorbs propagating fields. For\n evanescent fields, the PML can act as an amplification medium and cause a simulation to diverge. In Tidy3D,\n a warning will appear if the distance between a structure is smaller than half of a wavelength to prevent\n evanescent fields from leaking into PML. In most cases, the evanescent field will naturally die off within\n half a wavelength, but in some instances, a larger distance may be required.\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation1.png\n\n\n **References**\n\n .. [1] W.C. Chew and W.H. Weedon, Microwave and Optical Tech. Lett., 7 (13), 599,1994; S. Johnson, arXiv 2108.05348, 2021\n .. [2] Antonios Giannopoulos, IEEE Transactions on Antennas and Propagation, 56(9), 2995, 2008\n\nNote\n----\n\n For best results, structures that intersect with the PML or simulation edges should extend extend all the way\n through. In many such cases, an \u201cinfinite\u201d size ``td.inf`` can be used to define the size along that dimension.\n\nExample\n-------\n>>> pml = PML(num_layers=10)\n\nSee Also\n--------\n\n:class:`StablePML`:\n This PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PML", + "enum": [ + "PML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of standard PML.", + "default": 12, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "PML Parameters", + "description": "Parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "StablePML": { + "title": "StablePML", + "description": "Specifies a 'stable' PML along a single dimension.\nThis PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of 'stable' PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.0, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=5.0, alpha_order=1, alpha_min=0.0, alpha_max=0.9)\n 'Stable' parameters of the complex frequency-shifted absorption poles.\n\nExample\n-------\n>>> pml = StablePML(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "StablePML", + "enum": [ + "StablePML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of 'stable' PML.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Stable PML Parameters", + "description": "'Stable' parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.0, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 5.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.9 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "AbsorberParams": { + "title": "AbsorberParams", + "description": "Specifies parameters common to Absorbers and PMLs.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\n\nExample\n-------\n>>> params = AbsorberParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AbsorberParams", + "enum": [ + "AbsorberParams" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Absorber": { + "title": "Absorber", + "description": "Specifies an adiabatic absorber along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of absorber to add to + and - boundaries.\nparameters : AbsorberParams = AbsorberParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=6.4, type='AbsorberParams')\n Adiabatic absorber parameters.\n\nNotes\n-----\n\n This absorber is well-suited for dispersive materials intersecting with absorbing edges of the simulation at the\n expense of more layers.\n\n **Usage Caveats**\n\n Using absorber boundary is often a good remedy to resolve divergence issues related to :class:`PML`. The\n adiabatic absorber is a multilayer system with gradually increasing conductivity. The absorber usually has a\n larger undesired reflection compared to :class:`PML`. In practice, this small difference rarely matters,\n but is important to understand for simulations that require high accuracy.\n\n There are two possible sources for the reflection from absorbers. The first, and more common one, is that the\n ramping up of the conductivity is not sufficiently slow, which can be remedied by increasing the number of\n absorber layers (40 by default). The second one is that the absorption is not high enough, such that the\n light reaches the :class:`PEC` boundary at the end of the :class:`Absorber`, travels back through it,\n and is still not fully attenuated before re-entering the simulation region. If this is the case, increasing\n the maximum conductivity :class:`AbsorberParams` can help. In both cases, changing the order of the scaling\n of the conductivity (:attr:`tidy3d.AbsorberParams.sigma_order`) can also have an effect, but this is a more\n advanced setting that we typically do not recommend modifying.\n\nExample\n-------\n>>> pml = Absorber(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Absorber", + "enum": [ + "Absorber" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of absorber to add to + and - boundaries.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Absorber Parameters", + "description": "Adiabatic absorber parameters.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 6.4, + "type": "AbsorberParams" + }, + "allOf": [ + { + "$ref": "#/definitions/AbsorberParams" + } + ] + } + }, + "additionalProperties": false + }, + "BlochBoundary": { + "title": "BlochBoundary", + "description": "Specifies a Bloch boundary condition along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nbloch_vec : float\n Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.\n\nExample\n-------\n>>> bloch = BlochBoundary(bloch_vec=1)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "BlochBoundary", + "enum": [ + "BlochBoundary" + ], + "type": "string" + }, + "bloch_vec": { + "title": "Normalized Bloch vector component", + "description": "Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.", + "type": "number" + } + }, + "required": [ + "bloch_vec" + ], + "additionalProperties": false + }, + "Boundary": { + "title": "Boundary", + "description": "Boundary conditions at the minus and plus extents along a dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the plus side along a dimension.\nminus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the minus side along a dimension.\n\nNotes\n-----\n\n To specify individual boundary conditions along different dimensions, instead of :class:`BoundarySpec`,\n this class is used, which defines the ``plus`` and ``minus`` boundaries along a single\n dimension.\n\nExample\n-------\n>>> boundary = Boundary(plus = PML(), minus = PECBoundary())\n\nSee Also\n--------\n\n:class:`BoundarySpec`\n Specifies boundary conditions on each side of the domain and along each dimension.\n\n:class:`PML`\n A standard PML along a single dimension.\n\n**Notebooks**\n * `Setting up boundary conditions <../../notebooks/BoundaryConditions.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "plus": { + "title": "Plus BC", + "description": "Boundary condition on the plus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "minus": { + "title": "Minus BC", + "description": "Boundary condition on the minus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "type": { + "title": "Type", + "default": "Boundary", + "enum": [ + "Boundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "BoundarySpec": { + "title": "BoundarySpec", + "description": "Specifies boundary conditions on each side of the domain and along each dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nx : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\ny : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\nz : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\n\nNotes\n-----\n\n This :class:`BoundarySpec` object defines the boundary conditions applied on each of the 6 domain edges,\n and is provided as an input to the simulation.\n\n A :class:`BoundarySpec` consists of three :class:`Boundary` objects, each defining the boundaries on the plus\n and minus side of each dimension. In most cases, one just wants to specify whether there are absorbing\n :class:`PML` layers along any of the ``x``, ``y``, ``z`` dimensions. By default, ``tidy3d`` simulations have\n :class:`PML` boundaries on all sides.\n\n If we want to explicitly set the boundaries, we can use the :attr:`tidy3d.BoundarySpec.all_sides` method.\n This can be used to set any type of boundary condition on all sides of the simulation. We can also set\n :class:`PML` on specified sides only by calling the :attr:`tidy3d.BoundarySpec.pml` method, e.g. ``BoundarySpec.pml(\n x=False, y=False, z=False)``. This will put :class:`PML` along the dimensions defined as ``True``,\n and set periodic boundaries along the other dimensions.\n\n\nSee Also\n--------\n\n:class:`Boundary`\n Boundary conditions at the minus and plus extents along a dimension.\n\n**Notebooks**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures**\n * `Using FDTD to Compute a Transmission Spectrum `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "x": { + "title": "Boundary condition along x.", + "description": "Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "y": { + "title": "Boundary condition along y.", + "description": "Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "z": { + "title": "Boundary condition along z.", + "description": "Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "type": { + "title": "Type", + "default": "BoundarySpec", + "enum": [ + "BoundarySpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "EMEModeSolverMonitor": { + "title": "EMEModeSolverMonitor", + "description": "EME mode solver monitor.\nRecords EME modes computed in planes intersecting the monitor geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Note: the interval in the propagation direction is not used. Note: this is not yet supported.\neme_cell_interval_space : PositiveInt = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.\nnormalize : bool = True\n Whether to normalize the EME modes to unity flux.\nkeep_invalid_modes : bool = False\n Whether to store modes containing nan values and modes which are exponentially increasing in the propagation direction.\n\nNote\n----\n\n This is different than a :class:`.ModeSolverMonitor`, which computes modes within\n its planar geometry. In contrast, this monitor does not compute new modes; instead,\n it records the modes used for EME expansion and propagation, but only within the\n monitor geometry.\n\nExample\n-------\n>>> monitor = EMEModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_modes\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEModeSolverMonitor", + "enum": [ + "EMEModeSolverMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Note: the interval in the propagation direction is not used. Note: this is not yet supported.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.", + "default": true, + "type": "boolean" + }, + "normalize": { + "title": "Normalize Modes", + "description": "Whether to normalize the EME modes to unity flux.", + "default": true, + "type": "boolean" + }, + "keep_invalid_modes": { + "title": "Keep Invalid Modes", + "description": "Whether to store modes containing nan values and modes which are exponentially increasing in the propagation direction.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "EMEFieldMonitor": { + "title": "EMEFieldMonitor", + "description": "EME monitor for propagated field.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. For 'EMEFieldMonitor', refers to the number of modes at each port.Cannot exceed the max of the number of modes in the two ports. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\neme_cell_interval_space : Literal[1] = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1. Note: this field is not used for EME field monitor.\n\nExample\n-------\n>>> monitor = EMEFieldMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_field\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEFieldMonitor", + "enum": [ + "EMEFieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.", + "default": true, + "type": "boolean" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. For 'EMEFieldMonitor', refers to the number of modes at each port.Cannot exceed the max of the number of modes in the two ports. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1. Note: this field is not used for EME field monitor.", + "default": 1, + "enum": [ + 1 + ], + "type": "integer" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "EMECoefficientMonitor": { + "title": "EMECoefficientMonitor", + "description": "EME monitor for mode coefficients.\nRecords the amplitudes of the forward and backward modes in each cell\nintersecting the monitor geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1. Note: This field is not used for 'EMECoefficientMonitor'.\neme_cell_interval_space : PositiveInt = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid) on-the-fly during a solver run. Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\n\nExample\n-------\n>>> monitor = EMECoefficientMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_coeffs\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMECoefficientMonitor", + "enum": [ + "EMECoefficientMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1. Note: This field is not used for 'EMECoefficientMonitor'.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid) on-the-fly during a solver run. Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "ApodizationSpec": { + "title": "ApodizationSpec", + "description": "Stores specifications for the apodizaton of frequency-domain monitors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstart : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the start apodization ends.\nend : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the end apodization begins.\nwidth : Optional[PositiveFloat] = None\n [units = sec]. Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.\n\nExample\n-------\n>>> apod_spec = ApodizationSpec(start=1, end=2, width=0.2)\n\n\n.. image:: ../../_static/img/apodization.png\n :width: 80%\n :align: center", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "start": { + "title": "Start Interval", + "description": "Defines the time at which the start apodization ends.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "end": { + "title": "End Interval", + "description": "Defines the time at which the end apodization begins.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "width": { + "title": "Apodization Width", + "description": "Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ApodizationSpec", + "enum": [ + "ApodizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ModeSpec": { + "title": "ModeSpec", + "description": "Stores specifications for the mode solver to find an electromagntic mode.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\nprecision : Literal['auto', 'single', 'double'] = double\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = central\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.\n\nNotes\n-----\n\n The :attr:`angle_theta` and :attr:`angle_phi` parameters define the injection axis as illustrated in the figure\n below, with respect to the axis normal to the mode plane (``x`` in the figure). Note that :attr:`angle_theta`\n must be smaller than :math:`\\frac{pi}{2}`. To inject in the backward direction, we can still use the\n ``direction`` parameter as also shown in the figure. Similarly, the mode amplitudes computed in mode monitors\n are defined w.r.t. the ``forward`` and ``backward`` directions as illustrated. Note, the planar axes are\n found by popping the injection axis from ``{x,y,z}``. For example, if injection axis is ``y``, the planar\n axes are ordered ``{x,z}``.\n\n .. image:: ../../notebooks/img/ring_modes.png\n\n The :attr:`bend_axis` is the axis normal to the plane in which the bend lies, (``z`` in the diagram below). In\n the mode specification, it is defined locally for the mode plane as one of the two axes tangential to the\n plane. In the case of bends that lie in the ``xy``-plane, the mode plane would be either in ``xz`` or in\n ``yz``, so in both cases the correct setting is ``bend_axis=1``, selecting the global ``z``. The\n ``bend_radius`` is counted from the center of the mode plane to the center of the curvature,\n along the tangential axis perpendicular to the bend axis. This radius can also be negative, if the center of\n the mode plane is smaller than the center of the bend.\n\n .. image:: ../../notebooks/img/mode_angled.png\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Introduction on tidy3d working principles <../../notebooks/Primer.html#Modes>`_\n * `Defining mode sources and monitors <../../notebooks/ModalSourcesMonitors.html>`_\n * `Injecting modes in bent and angled waveguides <../../notebooks/ModesBentAngled.html>`_\n * `Waveguide to ring coupling <../../notebooks/WaveguideToRingCoupling.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_modes": { + "title": "Number of modes", + "description": "Number of modes returned by mode solver.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "target_neff": { + "title": "Target effective index", + "description": "Guess for effective index of the mode.", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_pml": { + "title": "Number of PML layers", + "description": "Number of standard pml layers to add in the two tangential axes.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ] + }, + "filter_pol": { + "title": "Polarization filtering", + "description": "The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.", + "enum": [ + "te", + "tm" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "precision": { + "title": "single, double, or automatic precision in mode solver", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "double", + "enum": [ + "auto", + "single", + "double" + ], + "type": "string" + }, + "bend_radius": { + "title": "Bend radius", + "description": "A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.", + "units": "um", + "type": "number" + }, + "bend_axis": { + "title": "Bend axis", + "description": "Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).", + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "angle_rotation": { + "title": "Use fields rotation when angle_theta is not zero", + "description": "Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.", + "default": false, + "type": "boolean" + }, + "track_freq": { + "title": "Mode Tracking Frequency", + "description": "Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.", + "default": "central", + "enum": [ + "central", + "lowest", + "highest" + ], + "type": "string" + }, + "group_index_step": { + "title": "Frequency step for group index computation", + "description": "Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "default": false, + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "boolean" + } + ] + }, + "type": { + "title": "Type", + "default": "ModeSpec", + "enum": [ + "ModeSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ModeSolverMonitor": { + "title": "ModeSolverMonitor", + "description": ":class:`Monitor` that stores the mode field profiles returned by the mode solver in the\nmonitor plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeSolverMonitor", + "enum": [ + "ModeSolverMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "store_fields_direction": { + "title": "Store Fields", + "description": "Propagation direction for the mode field profiles stored from mode solving.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "direction": { + "title": "Propagation Direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "PermittivityMonitor": { + "title": "PermittivityMonitor", + "description": ":class:`Monitor` that records the diagonal components of the complex-valued relative\npermittivity tensor in the frequency domain. The recorded data has the same shape as a\n:class:`.FieldMonitor` of the same geometry: the permittivity values are saved at the\nYee grid locations, and can be interpolated to any point inside the monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : Literal[False] = False\n Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n This field is ignored in this monitor.\n\nNotes\n-----\n\n If 2D materials are present, then the permittivity values correspond to the\n volumetric equivalent of the 2D materials.\n\n .. TODO add links to relevant areas\n\nExample\n-------\n>>> monitor = PermittivityMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='eps_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityMonitor", + "enum": [ + "PermittivityMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "This field is ignored in this monitor.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "UniformGrid": { + "title": "UniformGrid", + "description": "Uniform 1D grid. The most standard way to define a simulation is to use a constant grid size in each of the three directions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\n\nExample\n-------\n>>> grid_1d = UniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`QuasiUniformGrid`\n Specification for quasi-uniform grid along a given dimension.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Photonic crystal waveguide polarization filter <../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "UniformGrid", + "enum": [ + "UniformGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "CustomGrid": { + "title": "CustomGrid", + "description": "Custom 1D grid supplied as a list of grid cell sizes centered on the simulation center.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : Tuple[PositiveFloat, ...]\n [units = um]. An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.\ncustom_offset : Optional[float] = None\n [units = um]. The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.\n\nExample\n-------\n>>> grid_1d = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGrid", + "enum": [ + "CustomGrid" + ], + "type": "string" + }, + "dl": { + "title": "Customized grid sizes.", + "description": "An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.", + "units": "um", + "type": "array", + "items": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "custom_offset": { + "title": "Customized grid offset.", + "description": "The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.", + "units": "um", + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GradedMesher": { + "title": "GradedMesher", + "description": "Implements automatic nonuniform meshing with a set minimum steps per wavelength and\na graded mesh expanding from higher- to lower-resolution regions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GradedMesher", + "enum": [ + "GradedMesher" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AutoGrid": { + "title": "AutoGrid", + "description": "Specification for non-uniform grid along a given dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\nmin_steps_per_wvl : ConstrainedFloatValue = 10.0\n Minimal number of steps per wavelength in each medium.\nmin_steps_per_sim_size : ConstrainedFloatValue = 10.0\n Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.\n\nExample\n-------\n>>> grid_1d = AutoGrid(min_steps_per_wvl=16, max_scale=1.4)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`GridSpec`\n Collective grid specification for all three dimensions.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "AutoGrid", + "enum": [ + "AutoGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "min_steps_per_wvl": { + "title": "Minimal Number of Steps Per Wavelength", + "description": "Minimal number of steps per wavelength in each medium.", + "default": 10.0, + "minimum": 6.0, + "type": "number" + }, + "min_steps_per_sim_size": { + "title": "Minimal Number of Steps Per Simulation Domain Size", + "description": "Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.", + "default": 10.0, + "minimum": 1.0, + "type": "number" + } + }, + "additionalProperties": false + }, + "CustomGridBoundaries": { + "title": "CustomGridBoundaries", + "description": "Custom 1D grid supplied as a list of grid cell boundary coordinates.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncoords : ArrayLike[dtype=float, ndim=1]\n [units = um]. An array of grid boundary coordinates.\n\nExample\n-------\n>>> grid_1d = CustomGridBoundaries(coords=[-0.2, 0.0, 0.2, 0.4, 0.5, 0.6, 0.7])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGridBoundaries", + "enum": [ + "CustomGridBoundaries" + ], + "type": "string" + }, + "coords": { + "title": "Grid Boundary Coordinates", + "description": "An array of grid boundary coordinates.", + "units": "um", + "type": "ArrayLike" + } + }, + "required": [ + "coords" + ], + "additionalProperties": false + }, + "QuasiUniformGrid": { + "title": "QuasiUniformGrid", + "description": "Similar to :class:`UniformGrid` that generates uniform 1D grid, but grid positions\nare locally fine tuned to be snaped to snapping points and the edges of structure bounding boxes.\nInternally, it is using the same meshing method as :class:`AutoGrid`, but it ignores material information in\nfavor for a user-defined grid size.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\ndl : PositiveFloat\n [units = um]. Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.\n\nExample\n-------\n>>> grid_1d = QuasiUniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "QuasiUniformGrid", + "enum": [ + "QuasiUniformGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "MeshOverrideStructure": { + "title": "MeshOverrideStructure", + "description": "Defines an object that is only used in the process of generating the mesh.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : int = 0\n Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.\ndl : Tuple[PositiveFloat, PositiveFloat, PositiveFloat]\n [units = um]. Grid size along x, y, z directions.\nenforce : bool = False\n If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.\nshadow : bool = True\n In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.\ndrop_outside_sim : bool = True\n If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.\n\nNotes\n-----\n\n A :class:`MeshOverrideStructure` is a combination of geometry :class:`Geometry`,\n grid size along ``x``, ``y``, ``z`` directions, and a boolean on whether the override\n will be enforced.\n\nExample\n-------\n>>> from tidy3d import Box\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.", + "default": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "MeshOverrideStructure", + "enum": [ + "MeshOverrideStructure" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size along x, y, z directions.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + }, + "enforce": { + "title": "Enforce Grid Size", + "description": "If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.", + "default": false, + "type": "boolean" + }, + "shadow": { + "title": "Grid Size Choice In Structure Overlapping Region", + "description": "In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.", + "default": true, + "type": "boolean" + }, + "drop_outside_sim": { + "title": "Drop Structure Outside Simulation Domain", + "description": "If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "geometry", + "dl" + ], + "additionalProperties": false + }, + "GridRefinement": { + "title": "GridRefinement", + "description": "Specification for local mesh refinement that defines the grid step size and the number of grid\ncells in the refinement region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrefinement_factor : Optional[PositiveFloat] = None\n Refine grid step size in vacuum by this factor.\ndl : Optional[PositiveFloat] = None\n [units = um]. Grid step size in the refined region.\nnum_cells : PositiveInt = 3\n Number of grid cells in the refinement region.\n\nNote\n----\n\nIf both `refinement_factor` and `dl` are defined, the grid step size is upper bounded by the smaller value of the two.\nIf neither is defined, default `refinement_factor=2` is applied.\n\n\nExample\n-------\n>>> grid_refine = GridRefinement(refinement_factor = 2, num_cells = 7)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "refinement_factor": { + "title": "Mesh Refinement Factor", + "description": "Refine grid step size in vacuum by this factor.", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid step size in the refined region.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_cells": { + "title": "Number of Refined Grid Cells", + "description": "Number of grid cells in the refinement region.", + "default": 3, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "GridRefinement", + "enum": [ + "GridRefinement" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "CornerFinderSpec": { + "title": "CornerFinderSpec", + "description": "Specification for corner detection on a 2D plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmedium : Literal['metal', 'dielectric', 'all'] = metal\n Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.\nangle_threshold : ConstrainedFloatValue = 0.3141592653589793\n A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.\ndistance_threshold : Optional[PositiveFloat] = None\n If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.\nconcave_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nconvex_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nmixed_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "medium": { + "title": "Material Type For Corner Identification", + "description": "Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.", + "default": "metal", + "enum": [ + "metal", + "dielectric", + "all" + ], + "type": "string" + }, + "angle_threshold": { + "title": "Angle Threshold In Corner Identification", + "description": "A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.", + "default": 0.3141592653589793, + "exclusiveMaximum": 3.141592653589793, + "minimum": 0, + "type": "number" + }, + "distance_threshold": { + "title": "Distance Threshold In Corner Identification", + "description": "If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concave_resolution": { + "title": "Concave Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "convex_resolution": { + "title": "Convex Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mixed_resolution": { + "title": "Mixed Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "CornerFinderSpec", + "enum": [ + "CornerFinderSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LayerRefinementSpec": { + "title": "LayerRefinementSpec", + "description": "Specification for automatic mesh refinement and snapping in layered structures. Structure corners\non the cross section perpendicular to layer thickness direction can be automatically identified. Subsequently,\nmesh is snapped and refined around the corners. Mesh can also be refined and snapped around the bounds along\nthe layer thickness direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\naxis : Literal[0, 1, 2]\n Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).\nmin_steps_along_axis : Optional[PositiveFloat] = None\n If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.\nbounds_refinement : Optional[GridRefinement] = None\n If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.\nbounds_snapping : Optional[Literal['bounds', 'lower', 'upper', 'center']] = lower\n If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.\ncorner_finder : Optional[CornerFinderSpec] = CornerFinderSpec(attrs={}, medium='metal', angle_threshold=0.3141592653589793, distance_threshold=None, concave_resolution=None, convex_resolution=None, mixed_resolution=None, type='CornerFinderSpec')\n Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.\ncorner_snapping : bool = True\n If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.\ncorner_refinement : Optional[GridRefinement] = GridRefinement(attrs={}, refinement_factor=None, dl=None, num_cells=3, type='GridRefinement')\n If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. \nrefinement_inside_sim_only : bool = True\n If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.\ngap_meshing_iters : NonNegativeInt = 1\n Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.\ndl_min_from_gap_width : bool = True\n Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.\n\nNote\n----\n\nCorner detection is performed on a 2D plane sitting in the middle of the layer. If the layer is finite\nalong inplane axes, corners outside the bounds are discarded.\n\nNote\n----\n\nThis class only takes effect when :class:`AutoGrid` is applied.\n\nExample\n-------\n>>> layer_spec = LayerRefinementSpec(axis=2, center=(0,0,0), size=(2, 3, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LayerRefinementSpec", + "enum": [ + "LayerRefinementSpec" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "min_steps_along_axis": { + "title": "Minimal Number Of Steps Along Axis", + "description": "If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.", + "exclusiveMinimum": 0, + "type": "number" + }, + "bounds_refinement": { + "title": "Mesh Refinement Factor Around Layer Bounds", + "description": "If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.", + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "bounds_snapping": { + "title": "Placing Grid Snapping Point Along Axis", + "description": "If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.", + "default": "lower", + "enum": [ + "bounds", + "lower", + "upper", + "center" + ], + "type": "string" + }, + "corner_finder": { + "title": "Inplane Corner Detection Specification", + "description": "Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.", + "default": { + "attrs": {}, + "medium": "metal", + "angle_threshold": 0.3141592653589793, + "distance_threshold": null, + "concave_resolution": null, + "convex_resolution": null, + "mixed_resolution": null, + "type": "CornerFinderSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/CornerFinderSpec" + } + ] + }, + "corner_snapping": { + "title": "Placing Grid Snapping Point At Corners", + "description": "If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.", + "default": true, + "type": "boolean" + }, + "corner_refinement": { + "title": "Inplane Mesh Refinement Factor Around Corners", + "description": "If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. ", + "default": { + "attrs": {}, + "refinement_factor": null, + "dl": null, + "num_cells": 3, + "type": "GridRefinement" + }, + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "refinement_inside_sim_only": { + "title": "Apply Refinement Only To Features Inside Simulation Domain", + "description": "If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.", + "default": true, + "type": "boolean" + }, + "gap_meshing_iters": { + "title": "Gap Meshing Iterations", + "description": "Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "dl_min_from_gap_width": { + "title": "Set ``dl_min`` from Estimated Gap Width", + "description": "Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "size", + "axis" + ], + "additionalProperties": false + }, + "GridSpec": { + "title": "GridSpec", + "description": "Collective grid specification for all three dimensions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngrid_x : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along x-axis\ngrid_y : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along y-axis\ngrid_z : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along z-axis\nwavelength : Optional[float] = None\n [units = um]. Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.\noverride_structures : Tuple[Annotated[Union[tidy3d.components.structure.Structure, tidy3d.components.structure.MeshOverrideStructure], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nsnapping_points : Tuple[tuple[Optional[float], Optional[float], Optional[float]], ...] = ()\n A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nlayer_refinement_specs : Tuple[LayerRefinementSpec, ...] = ()\n Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.\n\nExample\n-------\n>>> uniform = UniformGrid(dl=0.1)\n>>> custom = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])\n>>> auto = AutoGrid(min_steps_per_wvl=12)\n>>> grid_spec = GridSpec(grid_x=uniform, grid_y=custom, grid_z=auto, wavelength=1.5)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "grid_x": { + "title": "Grid specification along x-axis", + "description": "Grid specification along x-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_y": { + "title": "Grid specification along y-axis", + "description": "Grid specification along y-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_z": { + "title": "Grid specification along z-axis", + "description": "Grid specification along z-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "wavelength": { + "title": "Free-space wavelength", + "description": "Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.", + "units": "um", + "type": "number" + }, + "override_structures": { + "title": "Grid specification override structures", + "description": "A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Structure": "#/definitions/Structure", + "MeshOverrideStructure": "#/definitions/MeshOverrideStructure" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Structure" + }, + { + "$ref": "#/definitions/MeshOverrideStructure" + } + ] + } + }, + "snapping_points": { + "title": "Grid specification snapping_points", + "description": "A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + } + }, + "layer_refinement_specs": { + "title": "Mesh Refinement In Layered Structures", + "description": "Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/LayerRefinementSpec" + } + }, + "type": { + "title": "Type", + "default": "GridSpec", + "enum": [ + "GridSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LumpedResistor": { + "title": "LumpedResistor", + "description": "Class representing a rectangular lumped resistor. Lumped resistors are appended to the list\nof structures in the simulation as :class:`Medium2D` with the appropriate conductivity given\ntheir size and voltage axis.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nresistance : PositiveFloat\n Resistance value in ohms.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LumpedResistor", + "enum": [ + "LumpedResistor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "resistance" + ], + "additionalProperties": false + }, + "CoaxialLumpedResistor": { + "title": "CoaxialLumpedResistor", + "description": "Class representing a coaxial lumped resistor. Lumped resistors are appended to the list of\nstructures in the simulation as :class:`Medium2D` with the appropriate conductivity given their\nsize and geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nresistance : PositiveFloat\n Resistance value in ohms.\ncenter : Tuple[float, float, float] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nouter_diameter : PositiveFloat\n [units = um]. Diameter of the outer concentric circle.\ninner_diameter : PositiveFloat\n [units = um]. Diameter of the inner concentric circle.\nnormal_axis : Literal[0, 1, 2]\n Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "CoaxialLumpedResistor", + "enum": [ + "CoaxialLumpedResistor" + ], + "type": "string" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "outer_diameter": { + "title": "Outer Diameter", + "description": "Diameter of the outer concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "inner_diameter": { + "title": "Inner Diameter", + "description": "Diameter of the inner concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "normal_axis": { + "title": "Normal Axis", + "description": "Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + } + }, + "required": [ + "name", + "resistance", + "outer_diameter", + "inner_diameter", + "normal_axis" + ], + "additionalProperties": false + }, + "RLCNetwork": { + "title": "RLCNetwork", + "description": "Class for representing a simple network consisting of a resistor, capacitor, and inductor.\nProvides additional functionality for representing the network as an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nresistance : Optional[PositiveFloat] = None\n Resistance value in ohms.\ncapacitance : Optional[PositiveFloat] = None\n Capacitance value in farads.\ninductance : Optional[PositiveFloat] = None\n Inductance value in henrys.\nnetwork_topology : Literal['series', 'parallel'] = series\n Describes whether network elements are connected in ``series`` or ``parallel``.\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "capacitance": { + "title": "Capacitance", + "description": "Capacitance value in farads.", + "unit": "farad", + "exclusiveMinimum": 0, + "type": "number" + }, + "inductance": { + "title": "Inductance", + "description": "Inductance value in henrys.", + "unit": "henry", + "exclusiveMinimum": 0, + "type": "number" + }, + "network_topology": { + "title": "Network Topology", + "description": "Describes whether network elements are connected in ``series`` or ``parallel``.", + "default": "series", + "enum": [ + "series", + "parallel" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "RLCNetwork", + "enum": [ + "RLCNetwork" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AdmittanceNetwork": { + "title": "AdmittanceNetwork", + "description": "Class for representing a network consisting of an arbitrary number of resistors,\ncapacitors, and inductors. The network is represented in the Laplace domain\nas an admittance function. Provides additional functionality for representing the network\nas an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\na : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.\nb : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.\n\nNotes\n-----\n\n The network is described by the supplied coefficients as an admittance function that relates\n voltage to the current in the Laplace domain and is equivalent to a frequency-dependent\n complex conductivity :math:`\\sigma(\\omega)`.\n\n .. math::\n I(s) = Y(s)V(s)\n\n .. math::\n Y(s) = \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}\n\n An equivalent :class:`.PoleResidue` medium is constructed using an equivalent frequency-dependent\n complex permittivity defined as\n\n .. math::\n \\epsilon(s) = \\epsilon_\\infty - \\frac{\\Delta}{\\epsilon_0 s}\n \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}.\n\n The admittance is scaled depending on the geometric properties of the lumped element by\n the scaling factor :math:`\\Delta`. Implementation is based on the equivalent medium introduced\n by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> R = 50\n>>> C = 1e-12\n>>> a = (1, R * C) # Coefficients for an RC parallel network\n>>> b = (R, 0)\n>>> RC_parallel = AdmittanceNetwork(a=a,\n... b=b\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "a": { + "title": "Numerator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "b": { + "title": "Denominator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "type": { + "title": "Type", + "default": "AdmittanceNetwork", + "enum": [ + "AdmittanceNetwork" + ], + "type": "string" + } + }, + "required": [ + "a", + "b" + ], + "additionalProperties": false + }, + "LinearLumpedElement": { + "title": "LinearLumpedElement", + "description": "Lumped element representing a network consisting of resistors, capacitors, and inductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nnetwork : Union[RLCNetwork, AdmittanceNetwork]\n The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Switches between the different methods for distributing the lumped element over the grid.\n\n\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP\n>>> linear_element = LinearLumpedElement(\n... center=[0, 0, 0],\n... size=[2, 0, 3],\n... voltage_axis=0,\n... network=RL_series,\n... name=\"LumpedRL\"\n... ) # doctest: +SKIP\n\n\nSee Also\n--------\n\n**Notebooks:**\n * `Using lumped elements in Tidy3D simulations <../../notebooks/LinearLumpedElements.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearLumpedElement", + "enum": [ + "LinearLumpedElement" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "network": { + "title": "Network", + "description": "The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.", + "discriminator": { + "propertyName": "type", + "mapping": { + "RLCNetwork": "#/definitions/RLCNetwork", + "AdmittanceNetwork": "#/definitions/AdmittanceNetwork" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/RLCNetwork" + }, + { + "$ref": "#/definitions/AdmittanceNetwork" + } + ] + }, + "dist_type": { + "title": "Distribute Type", + "description": "Switches between the different methods for distributing the lumped element over the grid.", + "default": "on", + "enum": [ + "off", + "laterally_only", + "on" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "network" + ], + "additionalProperties": false + }, + "Staircasing": { + "title": "Staircasing", + "description": "Apply staircasing scheme to material assignment of Yee grids on structure boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nFor PEC interface, the algorithm is based on:\n\n A. Taflove and S. C. Hagness, \"Computational electromagnetics: the\n finite-difference time-domain method\", Chapter 10.3 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Staircasing", + "enum": [ + "Staircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PolarizedAveraging": { + "title": "PolarizedAveraging", + "description": "Apply a polarized subpixel averaging method to dielectric boundaries, which\nis a phenomenological approximation of :class:`.ContourPathAveraging`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolarizedAveraging", + "enum": [ + "PolarizedAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContourPathAveraging": { + "title": "ContourPathAveraging", + "description": "Apply a contour-path subpixel averaging method to dielectric boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ContourPathAveraging", + "enum": [ + "ContourPathAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VolumetricAveraging": { + "title": "VolumetricAveraging", + "description": "Apply volumetric averaging scheme to material properties of Yee grids on structure boundaries.\nThe material property is averaged in the volume surrounding the Yee grid.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstaircase_normal_component : bool = True\n Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VolumetricAveraging", + "enum": [ + "VolumetricAveraging" + ], + "type": "string" + }, + "staircase_normal_component": { + "title": "Staircasing For Field Components Substantially Normal To Interface", + "description": "Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HeuristicPECStaircasing": { + "title": "HeuristicPECStaircasing", + "description": "Apply a variant of staircasing scheme to PEC boundaries: the electric field grid is set to PEC\nif the field is substantially parallel to the interface.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeuristicPECStaircasing", + "enum": [ + "HeuristicPECStaircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECConformal": { + "title": "PECConformal", + "description": "Apply a subpixel averaging method known as conformal mesh scheme to PEC boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.3\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.\n\nNote\n----\nThe algorithm is based on:\n\n S. Dey and R. Mittra, \"A locally conformal finite-difference\n time-domain (FDTD) algorithm for modeling three-dimensional\n perfectly conducting objects\",\n IEEE Microwave and Guided Wave Letters, 7(9), 273 (1997).\n\n S. Benkler, N. Chavannes and N. Kuster, \"A new 3-D conformal\n PEC FDTD scheme with user-defined geometric precision and derived\n stability criterion\",\n IEEE Transactions on Antennas and Propagation, 54(6), 1843 (2006).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PECConformal", + "enum": [ + "PECConformal" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.3, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SurfaceImpedance": { + "title": "SurfaceImpedance", + "description": "Apply 1st order (Leontovich) surface impedance boundary condition to\nstructure made of :class:`.LossyMetalMedium`.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.0\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedance", + "enum": [ + "SurfaceImpedance" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.0, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SubpixelSpec": { + "title": "SubpixelSpec", + "description": "Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndielectric : Union[Staircasing, PolarizedAveraging, ContourPathAveraging] = PolarizedAveraging(attrs={}, type='PolarizedAveraging')\n Subpixel averaging method applied to dielectric material interfaces.\nmetal : Union[Staircasing, VolumetricAveraging] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.\npec : Union[Staircasing, HeuristicPECStaircasing, PECConformal] = PECConformal(attrs={}, type='PECConformal', timestep_reduction=0.3, edge_singularity_correction=False)\n Subpixel averaging method applied to PEC structure interfaces.\npmc : Union[Staircasing, HeuristicPECStaircasing] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to PMC structure interfaces.\nlossy_metal : Union[Staircasing, VolumetricAveraging, SurfaceImpedance] = SurfaceImpedance(attrs={}, type='SurfaceImpedance', timestep_reduction=0.0, edge_singularity_correction=False)\n Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "dielectric": { + "title": "Subpixel Averaging Method For Dielectric Interfaces", + "description": "Subpixel averaging method applied to dielectric material interfaces.", + "default": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "PolarizedAveraging": "#/definitions/PolarizedAveraging", + "ContourPathAveraging": "#/definitions/ContourPathAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/PolarizedAveraging" + }, + { + "$ref": "#/definitions/ContourPathAveraging" + } + ] + }, + "metal": { + "title": "Subpixel Averaging Method For Metallic Interfaces", + "description": "Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + } + ] + }, + "pec": { + "title": "Subpixel Averaging Method For PEC Interfaces", + "description": "Subpixel averaging method applied to PEC structure interfaces.", + "default": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing", + "PECConformal": "#/definitions/PECConformal" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + }, + { + "$ref": "#/definitions/PECConformal" + } + ] + }, + "pmc": { + "title": "Subpixel Averaging Method For PMC Interfaces", + "description": "Subpixel averaging method applied to PMC structure interfaces.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + } + ] + }, + "lossy_metal": { + "title": "Subpixel Averaging Method for Lossy Metal Interfaces", + "description": "Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "default": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging", + "SurfaceImpedance": "#/definitions/SurfaceImpedance" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + }, + { + "$ref": "#/definitions/SurfaceImpedance" + } + ] + }, + "type": { + "title": "Type", + "default": "SubpixelSpec", + "enum": [ + "SubpixelSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "EMEModeSpec": { + "title": "EMEModeSpec", + "description": "Mode spec for EME cells. Overrides some of the defaults and allowed values.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : Literal[0.0] = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.\nangle_phi : Literal[0.0] = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.\nprecision : Literal['auto', 'single', 'double'] = auto\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = None\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed, which is the default for best performance.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_modes": { + "title": "Number of modes", + "description": "Number of modes returned by mode solver.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "target_neff": { + "title": "Target effective index", + "description": "Guess for effective index of the mode.", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_pml": { + "title": "Number of PML layers", + "description": "Number of standard pml layers to add in the two tangential axes.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ] + }, + "filter_pol": { + "title": "Polarization filtering", + "description": "The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.", + "enum": [ + "te", + "tm" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.", + "default": 0.0, + "units": "rad", + "enum": [ + 0.0 + ], + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.", + "default": 0.0, + "units": "rad", + "enum": [ + 0.0 + ], + "type": "number" + }, + "precision": { + "title": "single, double, or automatic precision in mode solver", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "auto", + "enum": [ + "auto", + "single", + "double" + ], + "type": "string" + }, + "bend_radius": { + "title": "Bend radius", + "description": "A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.", + "units": "um", + "type": "number" + }, + "bend_axis": { + "title": "Bend axis", + "description": "Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).", + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "angle_rotation": { + "title": "Use fields rotation when angle_theta is not zero", + "description": "Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.", + "default": false, + "type": "boolean" + }, + "track_freq": { + "title": "Mode Tracking Frequency", + "description": "Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed, which is the default for best performance.", + "enum": [ + "central", + "lowest", + "highest" + ], + "type": "string" + }, + "group_index_step": { + "title": "Frequency step for group index computation", + "description": "Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "default": false, + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "boolean" + } + ] + }, + "type": { + "title": "Type", + "default": "EMEModeSpec", + "enum": [ + "EMEModeSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "EMEUniformGrid": { + "title": "EMEUniformGrid", + "description": "Specification for a uniform EME grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nnum_cells : PositiveInt\n Number of cells in the uniform EME grid.\nmode_spec : EMEModeSpec\n Mode specification for the uniform EME grid.\n\nExample\n-------\n>>> from tidy3d import EMEModeSpec\n>>> mode_spec = EMEModeSpec(num_modes=10)\n>>> eme_grid = EMEUniformGrid(num_cells=10, mode_spec=mode_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMEUniformGrid", + "enum": [ + "EMEUniformGrid" + ], + "type": "string" + }, + "num_cells": { + "title": "Number of cells", + "description": "Number of cells in the uniform EME grid.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Mode specification for the uniform EME grid.", + "allOf": [ + { + "$ref": "#/definitions/EMEModeSpec" + } + ] + } + }, + "required": [ + "num_cells", + "mode_spec" + ], + "additionalProperties": false + }, + "EMEExplicitGrid": { + "title": "EMEExplicitGrid", + "description": "EME grid with explicitly defined internal boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nmode_specs : List[EMEModeSpec]\n Mode specifications for each cell in the explicit EME grid.\nboundaries : ArrayLike[dtype=float, ndim=1]\n List of coordinates of internal cell boundaries along the propagation axis. Must contain one fewer item than 'mode_specs', and must be strictly increasing. Each cell spans the region between an adjacent pair of boundaries. The first (last) cell spans the region between the first (last) boundary and the simulation boundary.\n\nExample\n-------\n>>> from tidy3d import EMEExplicitGrid, EMEModeSpec\n>>> mode_spec1 = EMEModeSpec(num_modes=10)\n>>> mode_spec2 = EMEModeSpec(num_modes=20)\n>>> eme_grid = EMEExplicitGrid(\n... mode_specs=[mode_spec1, mode_spec2],\n... boundaries=[1],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMEExplicitGrid", + "enum": [ + "EMEExplicitGrid" + ], + "type": "string" + }, + "mode_specs": { + "title": "Mode Specifications", + "description": "Mode specifications for each cell in the explicit EME grid.", + "type": "array", + "items": { + "$ref": "#/definitions/EMEModeSpec" + } + }, + "boundaries": { + "title": "Boundaries", + "description": "List of coordinates of internal cell boundaries along the propagation axis. Must contain one fewer item than 'mode_specs', and must be strictly increasing. Each cell spans the region between an adjacent pair of boundaries. The first (last) cell spans the region between the first (last) boundary and the simulation boundary.", + "type": "ArrayLike" + } + }, + "required": [ + "mode_specs", + "boundaries" + ], + "additionalProperties": false + }, + "EMECompositeGrid": { + "title": "EMECompositeGrid", + "description": "EME grid made out of multiple subgrids.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nsubgrids : ForwardRef('list[EMESubgridType]')\n Subgrids in the composite grid.\nsubgrid_boundaries : ArrayLike[dtype=float, ndim=1]\n List of coordinates of internal subgrid boundaries along the propagation axis. Must contain one fewer item than 'subgrids', and must be strictly increasing. Each subgrid spans the region between an adjacent pair of subgrid boundaries. The first (last) subgrid spans the region between the first (last) subgrid boundary and the simulation boundary.\n\nExample\n-------\n>>> from tidy3d import EMEUniformGrid, EMEModeSpec\n>>> mode_spec1 = EMEModeSpec(num_modes=10)\n>>> mode_spec2 = EMEModeSpec(num_modes=20)\n>>> subgrid1 = EMEUniformGrid(num_cells=5, mode_spec=mode_spec1)\n>>> subgrid2 = EMEUniformGrid(num_cells=10, mode_spec=mode_spec2)\n>>> eme_grid = EMECompositeGrid(\n... subgrids=[subgrid1, subgrid2],\n... subgrid_boundaries=[1]\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMECompositeGrid", + "enum": [ + "EMECompositeGrid" + ], + "type": "string" + }, + "subgrids": { + "title": "Subgrids", + "description": "Subgrids in the composite grid.", + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/EMEUniformGrid" + }, + { + "$ref": "#/definitions/EMEExplicitGrid" + }, + { + "$ref": "#/definitions/EMECompositeGrid" + } + ] + } + }, + "subgrid_boundaries": { + "title": "Subgrid Boundaries", + "description": "List of coordinates of internal subgrid boundaries along the propagation axis. Must contain one fewer item than 'subgrids', and must be strictly increasing. Each subgrid spans the region between an adjacent pair of subgrid boundaries. The first (last) subgrid spans the region between the first (last) subgrid boundary and the simulation boundary.", + "type": "ArrayLike" + } + }, + "required": [ + "subgrids", + "subgrid_boundaries" + ], + "additionalProperties": false + }, + "EMELengthSweep": { + "title": "EMELengthSweep", + "description": "Spec for sweeping EME cell lengths.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nscale_factors : ArrayLike\n Length scale factors to be used in the EME propagation step. The EME propagation step is repeated after scaling every cell length by this amount. The results are stored in 'sim_data.smatrix'. If a 2D array is provided, the first index is the sweep index and the second index is the cell index, allowing a nonuniform cell scaling along the propagation axis.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMELengthSweep", + "enum": [ + "EMELengthSweep" + ], + "type": "string" + }, + "scale_factors": { + "title": "Length Scale Factor", + "description": "Length scale factors to be used in the EME propagation step. The EME propagation step is repeated after scaling every cell length by this amount. The results are stored in 'sim_data.smatrix'. If a 2D array is provided, the first index is the sweep index and the second index is the cell index, allowing a nonuniform cell scaling along the propagation axis.", + "type": "ArrayLike" + } + }, + "required": [ + "scale_factors" + ], + "additionalProperties": false + }, + "EMEModeSweep": { + "title": "EMEModeSweep", + "description": "Spec for sweeping number of modes in EME propagation step.\nUsed for convergence testing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : ArrayLike[dtype=int, ndim=1]\n Max number of modes to use in the EME propagation step. The EME propagation step is repeated after dropping modes with mode_index exceeding this value. This can be used for convergence testing; reliable results should be independent of the number of modes used. This value cannot exceed the maximum number of modes in any EME cell in the simulation.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEModeSweep", + "enum": [ + "EMEModeSweep" + ], + "type": "string" + }, + "num_modes": { + "title": "Number of Modes", + "description": "Max number of modes to use in the EME propagation step. The EME propagation step is repeated after dropping modes with mode_index exceeding this value. This can be used for convergence testing; reliable results should be independent of the number of modes used. This value cannot exceed the maximum number of modes in any EME cell in the simulation.", + "type": "ArrayLike" + } + }, + "required": [ + "num_modes" + ], + "additionalProperties": false + }, + "EMEFreqSweep": { + "title": "EMEFreqSweep", + "description": "Spec for sweeping frequency in EME propagation step.\nUnlike ``sim.freqs``, the frequency sweep is approximate, using a\nperturbative mode solver relative to the simulation EME modes.\nThis can be a faster way to solve at a larger number of frequencies.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfreq_scale_factors : ArrayLike[dtype=float, ndim=1]\n Scale factors applied to every frequency in 'EMESimulation.freqs'. After applying the scale factors, the new modes are computed approximately using the exact modes as a basis. If there are multiple 'EMESimulation.freqs', the exact modes are computed at each of those frequencies, and then the scale factors are applied to each independently.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEFreqSweep", + "enum": [ + "EMEFreqSweep" + ], + "type": "string" + }, + "freq_scale_factors": { + "title": "Frequency Scale Factors", + "description": "Scale factors applied to every frequency in 'EMESimulation.freqs'. After applying the scale factors, the new modes are computed approximately using the exact modes as a basis. If there are multiple 'EMESimulation.freqs', the exact modes are computed at each of those frequencies, and then the scale factors are applied to each independently.", + "type": "ArrayLike" + } + }, + "required": [ + "freq_scale_factors" + ], + "additionalProperties": false + }, + "EMEPeriodicitySweep": { + "title": "EMEPeriodicitySweep", + "description": "Spec for sweeping number of repetitions of EME subgrids.\nUseful for simulating long periodic structures like Bragg gratings,\nas it allows the EME solver to reuse the modes and cell interface\nscattering matrices.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : List[dict[str, pydantic.v1.types.PositiveInt]]\n Number of periodic repetitions of named subgrids in this EME grid. At each sweep index, contains a dict mapping the name of a subgrid to the number of repetitions of that subgrid at that sweep index.\n\nCompared to setting ``num_reps`` directly in the ``eme_grid_spec``,\nthis sweep spec allows varying the number of repetitions,\neffectively simulating multiple structures in a single EME simulation.\n\nExample\n-------\n>>> n_list = [1, 50, 100]\n>>> sweep_spec = EMEPeriodicitySweep(num_reps=[{\"unit_cell\": n} for n in n_list])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEPeriodicitySweep", + "enum": [ + "EMEPeriodicitySweep" + ], + "type": "string" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of named subgrids in this EME grid. At each sweep index, contains a dict mapping the name of a subgrid to the number of repetitions of that subgrid at that sweep index.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "integer", + "exclusiveMinimum": 0 + } + } + } + }, + "required": [ + "num_reps" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/HeatChargeSimulation.json b/schemas/HeatChargeSimulation.json new file mode 100644 index 0000000000..eff2eb52cd --- /dev/null +++ b/schemas/HeatChargeSimulation.json @@ -0,0 +1,11281 @@ +{ + "title": "HeatChargeSimulation", + "description": "Defines thermoelectric simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, 1], Literal[0, 1], Literal[0, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).\nsources : Tuple[Annotated[Union[tidy3d.components.tcad.source.heat.HeatSource, tidy3d.components.tcad.source.coupled.HeatFromElectricSource, tidy3d.components.tcad.source.heat.UniformHeatSource], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of heat and/or charge sources.\nboundary_spec : Tuple[Annotated[Union[tidy3d.components.tcad.boundary.specification.HeatChargeBoundarySpec, tidy3d.components.tcad.boundary.specification.HeatBoundarySpec], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of boundary condition specifications.\nmonitors : Tuple[Annotated[Union[tidy3d.components.tcad.monitors.heat.TemperatureMonitor, tidy3d.components.tcad.monitors.charge.SteadyPotentialMonitor, tidy3d.components.tcad.monitors.charge.SteadyFreeCarrierMonitor, tidy3d.components.tcad.monitors.charge.SteadyEnergyBandMonitor, tidy3d.components.tcad.monitors.charge.SteadyElectricFieldMonitor, tidy3d.components.tcad.monitors.charge.SteadyCapacitanceMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Monitors in the simulation.\ngrid_spec : Union[UniformUnstructuredGrid, DistanceUnstructuredGrid]\n Grid specification for heat-charge simulation.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nanalysis_spec : Union[IsothermalSteadyChargeDCAnalysis, UnsteadyHeatAnalysis] = None\n The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.\n\nNotes\n-----\n A ``HeatChargeSimulation`` supports different types of simulations. It solves the\n heat and conduction equations using the Finite-Volume (FV) method. This solver\n determines the required computation physics according to the simulation scene definition.\n This is implemented in this way due to the strong multi-physics coupling.\n\nThe ``HeatChargeSimulation`` can solve multiple physics and the intention is to enable close thermo-electrical coupling.\n\nCurrently, this solver supports steady-state heat conduction where :math:`q` is the heat flux, :math:`k`\nis the thermal conductivity, and :math:`T` is the temperature.\n\n .. math::\n\n -\\nabla \\cdot (-k \\nabla T) = q\n\nIt is also possible to run transient heat simulations by specifying ``analysis_spec=UnsteadyHeatAnalysis(...)``. This adds\nthe temporal terms to the above equations:\n\n .. math::\n\n \\frac{\\partial \\rho c_p T}{\\partial t} -\\nabla \\cdot (k \\nabla(T)) = q\n\nwhere :math:`\\rho` is the density and :math:`c_p` is the specific heat capacity of the medium.\n\n\nThe steady-state electrical ``Conduction`` equation depends on the electric conductivity (:math:`\\sigma`) of a\nmedium, and the electric field (:math:`\\mathbf{E} = -\\nabla(\\psi)`) derived from electrical potential (:math:`\\psi`).\nCurrently, in this type of simulation, no current sources or sinks are supported.\n\n .. math::\n\n \\text{div}(\\sigma \\cdot \\nabla(\\psi)) = 0\n\n\nFor further details on what equations are solved in ``Charge`` simulations, refer to the :class:`SemiconductorMedium`.\n\nLet's understand how the physics solving is determined:\n\n .. list-table::\n :widths: 25 75\n :header-rows: 1\n\n * - Simulation Type\n - Example Configuration Settings\n * - ``Heat``\n - The heat equation is solved with specified heat sources,\n boundary conditions, etc. Structures should incorporate materials\n with defined heat properties.\n * - ``Conduction``\n - The electrical conduction equation is solved with\n specified boundary conditions such as ``SteadyVoltageBC``, ``SteadyCurrentBC``, ...\n * - ``Charge``\n - Drift-diffusion equations are solved for structures containing\n a defined :class:`SemiconductorMedium`. Insulators with a\n :class:`ChargeInsulatorMedium` can also be included. For these, only the\n electric potential field is calculated.\n\nExamples\n--------\nTo run a thermal (``Heat`` |:fire:|) simulation with a solid conductive structure:\n\n>>> import tidy3d as td\n>>> heat_sim = td.HeatChargeSimulation(\n... size=(3.0, 3.0, 3.0),\n... structures=[\n... td.Structure(\n... geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=td.Medium(\n... permittivity=2.0,\n... heat_spec=td.SolidSpec(\n... conductivity=1,\n... capacity=1,\n... )\n... ),\n... name=\"box\",\n... ),\n... ],\n... medium=td.Medium(permittivity=3.0, heat_spec=td.FluidSpec()),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.1),\n... sources=[td.HeatSource(rate=1, structures=[\"box\"])],\n... boundary_spec=[\n... td.HeatChargeBoundarySpec(\n... placement=td.StructureBoundary(structure=\"box\"),\n... condition=td.TemperatureBC(temperature=500),\n... )\n... ],\n... monitors=[td.TemperatureMonitor(size=(1, 2, 3), name=\"sample\")],\n... )\n\nTo run a drift-diffusion (``Charge`` |:zap:|) system:\n\n>>> import tidy3d as td\n>>> air = td.FluidMedium(\n... name=\"air\"\n... )\n>>> intrinsic_Si = td.material_library['cSi'].variants['Si_MultiPhysics'].medium.charge\n>>> Si_n = intrinsic_Si.updated_copy(N_d=1e16, name=\"Si_n\")\n>>> Si_p = intrinsic_Si.updated_copy(N_a=1e16, name=\"Si_p\")\n>>> n_side = td.Structure(\n... geometry=td.Box(center=(-0.5, 0, 0), size=(1, 1, 1)),\n... medium=Si_n,\n... name=\"n_side\"\n... )\n>>> p_side = td.Structure(\n... geometry=td.Box(center=(0.5, 0, 0), size=(1, 1, 1)),\n... medium=Si_p,\n... name=\"p_side\"\n... )\n>>> bc_v1 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[-1, 0, 0.5])),\n... placement=td.MediumMediumInterface(mediums=[air.name, Si_n.name]),\n... )\n>>> bc_v2 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),\n... placement=td.MediumMediumInterface(mediums=[air.name, Si_p.name]),\n... )\n>>> charge_sim = td.HeatChargeSimulation(\n... structures=[n_side, p_side],\n... medium=td.Medium(heat_spec=td.FluidSpec(), name=\"air\"),\n... monitors=[td.SteadyFreeCarrierMonitor(\n... center=(0, 0, 0), size=(td.inf, td.inf, 0), name=\"charge_mnt\", unstructured=True\n... )],\n... center=(0, 0, 0),\n... size=(3, 3, 3),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.05),\n... boundary_spec=[bc_v1, bc_v2],\n... analysis_spec=td.IsothermalSteadyChargeDCAnalysis(\n... tolerance_settings=td.ChargeToleranceSpec(rel_tol=1e5, abs_tol=3e3, max_iters=400),\n... convergence_dv=10),\n... )\n\n\nCoupling between ``Heat`` and electrical ``Conduction`` simulations is currently limited to 1-way.\nThis is specified by defining a heat source of type :class:`HeatFromElectricSource`. With this coupling, joule heating is\ncalculated as part of the solution to a ``Conduction`` simulation and translated into the ``Heat`` simulation.\n\nTwo common scenarios can use this coupling definition:\n 1. One in which BCs and sources are specified for both ``Heat`` and ``Conduction`` simulations.\n In this case one mesh will be generated and used for both the ``Conduction`` and ``Heat``\n simulations.\n 2. Only heat BCs/sources are provided. In this case, only the ``Heat`` equation will be solved.\n Before the simulation starts, it will try to load the heat source from file so a\n previously run ``Conduction`` simulations must have run previously. Since the Conduction\n and ``Heat`` meshes may differ, an interpolation between them will be performed prior to\n starting the ``Heat`` simulation.\n\nAdditional heat sources can be defined, in which case, they will be added on\ntop of the coupling heat source.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatChargeSimulation", + "enum": [ + "HeatChargeSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Heat and Charge sources", + "description": "List of heat and/or charge sources.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatSource": "#/definitions/HeatSource", + "HeatFromElectricSource": "#/definitions/HeatFromElectricSource", + "UniformHeatSource": "#/definitions/UniformHeatSource" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatSource" + }, + { + "$ref": "#/definitions/HeatFromElectricSource" + }, + { + "$ref": "#/definitions/UniformHeatSource" + } + ] + } + }, + "boundary_spec": { + "title": "Boundary Condition Specifications", + "description": "List of boundary condition specifications.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatChargeBoundarySpec": "#/definitions/HeatChargeBoundarySpec", + "HeatBoundarySpec": "#/definitions/HeatBoundarySpec" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatChargeBoundarySpec" + }, + { + "$ref": "#/definitions/HeatBoundarySpec" + } + ] + } + }, + "monitors": { + "title": "Monitors", + "description": "Monitors in the simulation.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureMonitor": "#/definitions/TemperatureMonitor", + "SteadyPotentialMonitor": "#/definitions/SteadyPotentialMonitor", + "SteadyFreeCarrierMonitor": "#/definitions/SteadyFreeCarrierMonitor", + "SteadyEnergyBandMonitor": "#/definitions/SteadyEnergyBandMonitor", + "SteadyElectricFieldMonitor": "#/definitions/SteadyElectricFieldMonitor", + "SteadyCapacitanceMonitor": "#/definitions/SteadyCapacitanceMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureMonitor" + }, + { + "$ref": "#/definitions/SteadyPotentialMonitor" + }, + { + "$ref": "#/definitions/SteadyFreeCarrierMonitor" + }, + { + "$ref": "#/definitions/SteadyEnergyBandMonitor" + }, + { + "$ref": "#/definitions/SteadyElectricFieldMonitor" + }, + { + "$ref": "#/definitions/SteadyCapacitanceMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Grid specification for heat-charge simulation.", + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformUnstructuredGrid": "#/definitions/UniformUnstructuredGrid", + "DistanceUnstructuredGrid": "#/definitions/DistanceUnstructuredGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformUnstructuredGrid" + }, + { + "$ref": "#/definitions/DistanceUnstructuredGrid" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "analysis_spec": { + "title": "Analysis specification.", + "description": "The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/IsothermalSteadyChargeDCAnalysis" + }, + { + "$ref": "#/definitions/UnsteadyHeatAnalysis" + } + ] + } + }, + "required": [ + "size", + "grid_spec" + ], + "additionalProperties": false, + "definitions": { + "NonlinearSusceptibility": { + "title": "NonlinearSusceptibility", + "description": "Model for an instantaneous nonlinear chi3 susceptibility.\nThe expression for the instantaneous nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nchi3 : float = 0\n [units = um^2 / V^2]. Chi3 nonlinear susceptibility.\nnumiters : Optional[PositiveInt] = None\n Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\chi_3` must be real.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "NonlinearSusceptibility", + "enum": [ + "NonlinearSusceptibility" + ], + "type": "string" + }, + "chi3": { + "title": "Chi3", + "description": "Chi3 nonlinear susceptibility.", + "default": 0, + "units": "um^2 / V^2", + "type": "number" + }, + "numiters": { + "title": "Number of iterations", + "description": "Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.", + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "additionalProperties": false + }, + "ComplexNumber": { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + "TwoPhotonAbsorption": { + "title": "TwoPhotonAbsorption", + "description": "Model for two-photon absorption (TPA) nonlinearity which gives an intensity-dependent\nabsorption of the form :math:`\\alpha = \\alpha_0 + \\beta I`.\nAlso includes free-carrier absorption (FCA) and free-carrier plasma dispersion (FCPD) effects.\nThe expression for the nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nbeta : Union[float, tidycomplex, ComplexNumber] = 0\n [units = um / W]. Coefficient for two-photon absorption (TPA).\ntau : NonNegativeFloat = 0\n [units = sec]. Lifetime for the free carriers created by two-photon absorption (TPA).\nsigma : NonNegativeFloat = 0\n [units = um^2]. Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.\ne_e : NonNegativeFloat = 1\n Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\ne_h : NonNegativeFloat = 1\n Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_e : float = 0\n [units = um^(3 e_e)]. Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_h : float = 0\n [units = um^(3 e_h)]. Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\nfreq0 : Optional[PositiveFloat] = None\n Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\beta` must be real.\n\n .. math::\n\n P_{NL} = P_{TPA} + P_{FCA} + P_{FCPD} \\\\\n P_{TPA} = -\\frac{4}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{2 i \\omega} |E|^2 E \\\\\n P_{FCA} = -\\frac{c_0 \\varepsilon_0 n_0 \\sigma N_f}{i \\omega} E \\\\\n \\frac{dN_f}{dt} = \\frac{8}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{8 q_e \\hbar \\omega} |E|^4 - \\frac{N_f}{\\tau} \\\\\n N_e = N_h = N_f \\\\\n P_{FCPD} = \\varepsilon_0 2 n_0 \\Delta n (N_f) E \\\\\n \\Delta n (N_f) = (c_e N_e^{e_e} + c_h N_h^{e_h})\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n The implementation is described in::\n\n N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si\n High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> tpa_model = TwoPhotonAbsorption(beta=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TwoPhotonAbsorption", + "enum": [ + "TwoPhotonAbsorption" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "beta": { + "title": "TPA coefficient", + "description": "Coefficient for two-photon absorption (TPA).", + "default": 0, + "units": "um / W", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "tau": { + "title": "Carrier lifetime", + "description": "Lifetime for the free carriers created by two-photon absorption (TPA).", + "default": 0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "sigma": { + "title": "FCA cross section", + "description": "Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.", + "default": 0, + "units": "um^2", + "minimum": 0, + "type": "number" + }, + "e_e": { + "title": "Electron exponent", + "description": "Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "e_h": { + "title": "Hole exponent", + "description": "Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "c_e": { + "title": "Electron coefficient", + "description": "Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_e)", + "type": "number" + }, + "c_h": { + "title": "Hole coefficient", + "description": "Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_h)", + "type": "number" + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "freq0": { + "title": "Central frequency", + "description": "Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "KerrNonlinearity": { + "title": "KerrNonlinearity", + "description": "Model for Kerr nonlinearity which gives an intensity-dependent refractive index\nof the form :math:`n = n_0 + n_2 I`. The expression for the nonlinear polarization\nis given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nn2 : Union[tidycomplex, ComplexNumber] = 0\n [units = um^2 / W]. Nonlinear refractive index in the Kerr nonlinearity.\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\n_2` must be real.\n\n This model is equivalent to a :class:`.NonlinearSusceptibility`; the\n relation between the parameters is given below.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E \\\\\n n_2 = \\frac{3}{4 n_0^2 \\varepsilon_0 c_0} \\chi_3\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n To simulate nonlinear loss, consider instead using a :class:`.TwoPhotonAbsorption`\n model, which implements a more physical dispersive loss of the form\n :math:`\\chi_{TPA} = i \\frac{c_0 n_0 \\beta}{\\omega} I`.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> kerr_model = KerrNonlinearity(n2=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "KerrNonlinearity", + "enum": [ + "KerrNonlinearity" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "n2": { + "title": "Nonlinear refractive index", + "description": "Nonlinear refractive index in the Kerr nonlinearity.", + "default": 0, + "units": "um^2 / W", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "additionalProperties": false + }, + "NonlinearSpec": { + "title": "NonlinearSpec", + "description": "Abstract specification for adding nonlinearities to a medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmodels : Tuple[Union[NonlinearSusceptibility, TwoPhotonAbsorption, KerrNonlinearity], ...] = ()\n The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.\nnum_iters : PositiveInt = 5\n Number of iterations for solving nonlinear constitutive relation.\n\nNote\n----\nThe nonlinear constitutive relation is solved iteratively; it may not converge\nfor strong nonlinearities. Increasing ``num_iters`` can help with convergence.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)\n>>> nonlinear_spec = NonlinearSpec(models=[nonlinear_susceptibility])\n>>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "models": { + "title": "Nonlinear models", + "description": "The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSusceptibility" + }, + { + "$ref": "#/definitions/TwoPhotonAbsorption" + }, + { + "$ref": "#/definitions/KerrNonlinearity" + } + ] + } + }, + "num_iters": { + "title": "Number of iterations", + "description": "Number of iterations for solving nonlinear constitutive relation.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "NonlinearSpec", + "enum": [ + "NonlinearSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SpaceModulation": { + "title": "SpaceModulation", + "description": "The modulation profile with a user-supplied spatial distribution of\namplitude and phase.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : Union[float, SpatialDataArray] = 1\n Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.\nphase : Union[float, SpatialDataArray] = 0\n [units = rad]. Phase of modulation that can vary spatially.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Method of interpolation to use to obtain values at spatial locations on the Yee grids.\n\nNote\n----\n.. math::\n\n amp\\_space(r) = amplitude(r) \\cdot e^{i \\cdot phase(r)}\n\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> amp = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> phase = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> space = SpaceModulation(amplitude=amp, phase=phase)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SpaceModulation", + "enum": [ + "SpaceModulation" + ], + "type": "string" + }, + "amplitude": { + "title": "Amplitude of modulation in space", + "description": "Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.", + "default": 1, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "phase": { + "title": "Phase of modulation in space", + "description": "Phase of modulation that can vary spatially.", + "default": 0, + "units": "rad", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Method of interpolation to use to obtain values at spatial locations on the Yee grids.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContinuousWaveTimeModulation": { + "title": "ContinuousWaveTimeModulation", + "description": "Class describing modulation with a harmonic time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Modulation frequency.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t}\n\nNote\n----\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\n\nExample\n-------\n>>> cw = ContinuousWaveTimeModulation(freq0=200e12, amplitude=1, phase=0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWaveTimeModulation", + "enum": [ + "ContinuousWaveTimeModulation" + ], + "type": "string" + }, + "freq0": { + "title": "Modulation Frequency", + "description": "Modulation frequency.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "freq0" + ], + "additionalProperties": false + }, + "SpaceTimeModulation": { + "title": "SpaceTimeModulation", + "description": "Space-time modulation applied to a medium, adding\non top of the time-independent part.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nspace_modulation : SpaceModulation = SpaceModulation(attrs={}, type='SpaceModulation', amplitude=1.0, phase=0.0, interp_method='nearest')\n Space modulation part from the separable SpaceTimeModulation.\ntime_modulation : ContinuousWaveTimeModulation\n Time modulation part from the separable SpaceTimeModulation.\n\n\nNote\n----\nThe space-time modulation must be separable in space and time.\ne.g. when applied to permittivity,\n\n.. math::\n\n \\delta \\epsilon(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "space_modulation": { + "title": "Space modulation", + "description": "Space modulation part from the separable SpaceTimeModulation.", + "default": { + "attrs": {}, + "type": "SpaceModulation", + "amplitude": 1.0, + "phase": 0.0, + "interp_method": "nearest" + }, + "allOf": [ + { + "$ref": "#/definitions/SpaceModulation" + } + ] + }, + "time_modulation": { + "title": "Time modulation", + "description": "Time modulation part from the separable SpaceTimeModulation.", + "allOf": [ + { + "$ref": "#/definitions/ContinuousWaveTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "SpaceTimeModulation", + "enum": [ + "SpaceTimeModulation" + ], + "type": "string" + } + }, + "required": [ + "time_modulation" + ], + "additionalProperties": false + }, + "ModulationSpec": { + "title": "ModulationSpec", + "description": "Specification adding space-time modulation to the non-dispersive part of medium\nincluding relative permittivity at infinite frequency and electric conductivity.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npermittivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.\nconductivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of electric conductivity applied on top of the base conductivity.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "permittivity": { + "title": "Space-time modulation of relative permittivity", + "description": "Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "conductivity": { + "title": "Space-time modulation of conductivity", + "description": "Space-time modulation of electric conductivity applied on top of the base conductivity.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "ModulationSpec", + "enum": [ + "ModulationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VisualizationSpec": { + "title": "VisualizationSpec", + "description": "Defines specification for visualization when used with plotting functions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfacecolor : str = \n Color applied to the faces in visualization.\nedgecolor : Optional[str] = \n Color applied to the edges in visualization.\nalpha : Optional[ConstrainedFloatValue] = 1.0\n Opacity/alpha value in plotting between 0 and 1.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "facecolor": { + "title": "Face color", + "description": "Color applied to the faces in visualization.", + "default": "", + "type": "string" + }, + "edgecolor": { + "title": "Edge color", + "description": "Color applied to the edges in visualization.", + "default": "", + "type": "string" + }, + "alpha": { + "title": "Opacity", + "description": "Opacity/alpha value in plotting between 0 and 1.", + "default": 1.0, + "minimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "VisualizationSpec", + "enum": [ + "VisualizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FluidSpec": { + "title": "FluidSpec", + "description": "Fluid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidSpec", + "enum": [ + "FluidSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SolidSpec": { + "title": "SolidSpec", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidSpec", + "enum": [ + "SolidSpec" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "SolidMedium": { + "title": "SolidMedium", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidMedium", + "enum": [ + "SolidMedium" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "FluidMedium": { + "title": "FluidMedium", + "description": "Fluid medium. Heat simulations will not solve for temperature\nin a structure that has a medium with this 'heat_spec'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\n\nExample\n-------\n>>> solid = FluidMedium()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidMedium", + "enum": [ + "FluidMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Medium": { + "title": "Medium", + "description": "Dispersionless medium. Mediums define the optical properties of the materials within the simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n In a dispersion-less medium, the displacement field :math:`D(t)` reacts instantaneously to the applied\n electric field :math:`E(t)`.\n\n .. math::\n\n D(t) = \\epsilon E(t)\n\nExample\n-------\n>>> dielectric = Medium(permittivity=4.0, name='my_medium')\n>>> eps = dielectric.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Introduction on Tidy3D working principles <../../notebooks/Primer.html#Mediums>`_\n * `Index <../../notebooks/docs/features/medium.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_\n\n**GUI**\n * `Mediums `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium", + "enum": [ + "Medium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "additionalProperties": false + }, + "HammerstadSurfaceRoughness": { + "title": "HammerstadSurfaceRoughness", + "description": "Modified Hammerstad surface roughness model. It's a popular model that works well\nunder 5 GHz for surface roughness below 2 micrometer RMS.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrq : PositiveFloat\n [units = um]. RMS peak-to-valley height (Rq) of the surface roughness.\nroughness_factor : ConstrainedFloatValue = 2.0\n Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n 1 + (RF-1) \\frac{2}{\\pi}\\arctan(1.4\\frac{R_q^2}{\\delta^2})\n\n where :math:`\\delta` is skin depth, :math:`R_q` the RMS peak-to-vally height, and RF\n roughness factor.\n\nNote\n----\nThis model is based on:\n\n Y. Shlepnev, C. Nwachukwu, \"Roughness characterization for interconnect analysis\",\n 2011 IEEE International Symposium on Electromagnetic Compatibility,\n (DOI: 10.1109/ISEMC.2011.6038367), 2011.\n\n V. Dmitriev-Zdorov, B. Simonovich, I. Kochikov, \"A Causal Conductor Roughness Model\n and its Effect on Transmission Line Characteristics\", Signal Integrity Journal, 2018.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HammerstadSurfaceRoughness", + "enum": [ + "HammerstadSurfaceRoughness" + ], + "type": "string" + }, + "rq": { + "title": "RMS Peak-to-Valley Height", + "description": "RMS peak-to-valley height (Rq) of the surface roughness.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "roughness_factor": { + "title": "Roughness Factor", + "description": "Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.", + "default": 2.0, + "exclusiveMinimum": 1.0, + "type": "number" + } + }, + "required": [ + "rq" + ], + "additionalProperties": false + }, + "HuraySurfaceRoughness": { + "title": "HuraySurfaceRoughness", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HuraySurfaceRoughness", + "enum": [ + "HuraySurfaceRoughness" + ], + "type": "string" + }, + "relative_area": { + "title": "Relative Area", + "description": "Relative area of the matte base compared to a flat surface", + "default": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients for surface ratio and sphere radius", + "description": "List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.", + "units": [ + null, + "um" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "SurfaceImpedanceFitterParam": { + "title": "SurfaceImpedanceFitterParam", + "description": "Advanced parameters for fitting surface impedance of a :class:`.LossyMetalMedium`.\nInternally, the quantity to be fitted is surface impedance divided by ``-1j * \\omega``.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_num_poles : PositiveInt = 5\n Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.\ntolerance_rms : NonNegativeFloat = 0.001\n Tolerance in fitting.\nfrequency_sampling_points : PositiveInt = 20\n Number of sampling frequencies used in fitting.\nlog_sampling : bool = True\n Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "max_num_poles": { + "title": "Maximal Number Of Poles", + "description": "Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "tolerance_rms": { + "title": "Tolerance In Fitting", + "description": "Tolerance in fitting.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "frequency_sampling_points": { + "title": "Number Of Sampling Frequencies", + "description": "Number of sampling frequencies used in fitting.", + "default": 20, + "exclusiveMinimum": 0, + "type": "integer" + }, + "log_sampling": { + "title": "Frequencies Sampling In Log Scale", + "description": "Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedanceFitterParam", + "enum": [ + "SurfaceImpedanceFitterParam" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LossyMetalMedium": { + "title": "LossyMetalMedium", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Frequency range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "LossyMetalMedium", + "enum": [ + "LossyMetalMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "enum": [ + 1 + ], + "type": "integer" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "roughness": { + "title": "Surface Roughness Model", + "description": "Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.", + "discriminator": { + "propertyName": "type", + "mapping": { + "HammerstadSurfaceRoughness": "#/definitions/HammerstadSurfaceRoughness", + "HuraySurfaceRoughness": "#/definitions/HuraySurfaceRoughness" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HammerstadSurfaceRoughness" + }, + { + "$ref": "#/definitions/HuraySurfaceRoughness" + } + ] + }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "fit_param": { + "title": "Fitting Parameters For Surface Impedance", + "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", + "default": { + "attrs": {}, + "max_num_poles": 5, + "tolerance_rms": 0.001, + "frequency_sampling_points": 20, + "log_sampling": true, + "type": "SurfaceImpedanceFitterParam" + }, + "allOf": [ + { + "$ref": "#/definitions/SurfaceImpedanceFitterParam" + } + ] + } + }, + "required": [ + "frequency_range" + ], + "additionalProperties": false + }, + "PoleResidue": { + "title": "PoleResidue", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PoleResidue", + "enum": [ + "PoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + } + }, + "additionalProperties": false + }, + "Sellmeier": { + "title": "Sellmeier", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Sellmeier", + "enum": [ + "Sellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Lorentz": { + "title": "Lorentz", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Lorentz", + "enum": [ + "Lorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number", + "minimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Debye": { + "title": "Debye", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Debye", + "enum": [ + "Debye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Drude": { + "title": "Drude", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Drude", + "enum": [ + "Drude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "PECMedium": { + "title": "PECMedium", + "description": "Perfect electrical conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PECs, must import ``tidy3d.PEC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PECMedium", + "enum": [ + "PECMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AnisotropicMedium": { + "title": "AnisotropicMedium", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMedium", + "enum": [ + "AnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "FullyAnisotropicMedium": { + "title": "FullyAnisotropicMedium", + "description": "Fully anisotropic medium including all 9 components of the permittivity and conductivity\ntensors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]\n [units = None (relative permittivity)]. Relative permittivity tensor.\nconductivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n [units = S/um]. Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n Provided permittivity tensor and the symmetric part of the conductivity tensor must\n have coinciding main directions. A non-symmetric conductivity tensor can be used to model\n magneto-optic effects. Note that dispersive properties and subpixel averaging are currently not\n supported for fully anisotropic materials.\n\nNote\n----\n\n Simulations involving fully anisotropic materials are computationally more intensive, thus,\n they take longer time to complete. This increase strongly depends on the filling fraction of\n the simulation domain by fully anisotropic materials, varying approximately in the range from\n 1.5 to 5. The cost of running a simulation is adjusted correspondingly.\n\nExample\n-------\n>>> perm = [[2, 0, 0], [0, 1, 0], [0, 0, 3]]\n>>> cond = [[0.1, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> anisotropic_dielectric = FullyAnisotropicMedium(permittivity=perm, conductivity=cond)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "FullyAnisotropicMedium", + "enum": [ + "FullyAnisotropicMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity tensor.", + "default": [ + [ + 1, + 0, + 0 + ], + [ + 0, + 1, + 0 + ], + [ + 0, + 0, + 1 + ] + ], + "units": "None (relative permittivity)", + "type": "ArrayLike" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "units": "S/um", + "type": "ArrayLike" + } + }, + "additionalProperties": false + }, + "PermittivityDataset": { + "title": "PermittivityDataset", + "description": "Dataset storing the diagonal components of the permittivity tensor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\neps_xx : ScalarFieldDataArray\n Spatial distribution of the xx-component of the relative permittivity.\neps_yy : ScalarFieldDataArray\n Spatial distribution of the yy-component of the relative permittivity.\neps_zz : ScalarFieldDataArray\n Spatial distribution of the zz-component of the relative permittivity.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> sclr_fld = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = PermittivityDataset(eps_xx=sclr_fld, eps_yy=sclr_fld, eps_zz=sclr_fld)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityDataset", + "enum": [ + "PermittivityDataset" + ], + "type": "string" + }, + "eps_xx": { + "title": "DataArray", + "description": "Spatial distribution of the xx-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_yy": { + "title": "DataArray", + "description": "Spatial distribution of the yy-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_zz": { + "title": "DataArray", + "description": "Spatial distribution of the zz-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "eps_xx", + "eps_yy", + "eps_zz" + ], + "additionalProperties": false + }, + "TriangularGridDataset": { + "title": "TriangularGridDataset", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangularGridDataset", + "enum": [ + "TriangularGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "normal_axis": { + "title": "Grid Axis", + "description": "Orientation of the grid.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "normal_pos": { + "title": "Position", + "description": "Coordinate of the grid along the normal direction.", + "type": "number" + } + }, + "required": [ + "points", + "values", + "cells", + "normal_axis", + "normal_pos" + ], + "additionalProperties": false + }, + "TetrahedralGridDataset": { + "title": "TetrahedralGridDataset", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TetrahedralGridDataset", + "enum": [ + "TetrahedralGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "points", + "values", + "cells" + ], + "additionalProperties": false + }, + "CustomMedium": { + "title": "CustomMedium", + "description": ":class:`.Medium` with user-supplied permittivity distribution.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\neps_dataset : Optional[PermittivityDataset] = None\n [To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.\npermittivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = None (relative permittivity)]. Spatial profile of relative permittivity.\nconductivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = S/um]. Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> dielectric = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> eps = dielectric.eps_model(200e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomMedium", + "enum": [ + "CustomMedium" + ], + "type": "string" + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + }, + "eps_dataset": { + "title": "Permittivity Dataset", + "description": "[To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.", + "allOf": [ + { + "$ref": "#/definitions/PermittivityDataset" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Spatial profile of relative permittivity.", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "units": "S/um", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + }, + "additionalProperties": false + }, + "CustomPoleResidue": { + "title": "CustomPoleResidue", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomPoleResidue", + "enum": [ + "CustomPoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf" + ], + "additionalProperties": false + }, + "CustomSellmeier": { + "title": "CustomSellmeier", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomSellmeier", + "enum": [ + "CustomSellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "CustomLorentz": { + "title": "CustomLorentz", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomLorentz", + "enum": [ + "CustomLorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDebye": { + "title": "CustomDebye", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDebye", + "enum": [ + "CustomDebye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDrude": { + "title": "CustomDrude", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDrude", + "enum": [ + "CustomDrude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomAnisotropicMedium": { + "title": "CustomAnisotropicMedium", + "description": "Diagonally anisotropic medium with spatially varying permittivity in each component.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\ninterp_method : Optional[Literal['nearest', 'linear']] = None\n When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.\nsubpixel : Optional[bool] = None\n This field is ignored. Please set ``subpixel`` in each component\n\nNote\n----\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> x = np.linspace(-1, 1, Nx)\n>>> y = np.linspace(-1, 1, Ny)\n>>> z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=x, y=y, z=z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> medium_xx = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> medium_yy = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> d_epsilon = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> medium_zz = CustomLorentz(eps_inf=permittivity, coeffs=[(d_epsilon,f,delta),])\n>>> anisotropic_dielectric = CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomAnisotropicMedium", + "enum": [ + "CustomAnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This field is ignored. Please set ``subpixel`` in each component", + "type": "boolean" + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "LinearHeatPerturbation": { + "title": "LinearHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a linear function of\ntemperature.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n [units = K]. Temperature range in which perturbation model is valid.\ntemperature_ref : NonNegativeFloat\n [units = K]. Temperature at which perturbation is zero.\ncoeff : Union[float, tidycomplex, ComplexNumber]\n [units = 1/K]. Sensitivity (derivative) of perturbation with respect to temperature.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{coeff} \\times (T - \\text{temperature\\_ref}),\n\n where ``coeff`` is the parameter's sensitivity (thermo-optic coefficient) to temperature and\n ``temperature_ref`` is the reference temperature point. A temperature range in which such\n a model is deemed accurate may be provided as a field ``temperature_range``\n (default: ``[0, inf]``). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.0001,\n... temperature_range=[200, 500],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearHeatPerturbation", + "enum": [ + "LinearHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "temperature_ref": { + "title": "Reference temperature", + "description": "Temperature at which perturbation is zero.", + "units": "K", + "minimum": 0, + "type": "number" + }, + "coeff": { + "title": "Thermo-optic Coefficient", + "description": "Sensitivity (derivative) of perturbation with respect to temperature.", + "units": "1/K", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "required": [ + "temperature_ref", + "coeff" + ], + "additionalProperties": false + }, + "CustomHeatPerturbation": { + "title": "CustomHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a custom function of\ntemperature defined as an array of perturbation values at sample temperature points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n [units = K]. Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.\nperturbation_values : HeatDataArray\n Sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\n Notes\n -----\n\n The linear\n interpolation is used to calculate perturbation values between sample temperature points. For\n temperature values outside of the provided sample region the perturbation value is extrapolated\n as a constant.\n The temperature range, ``temperature_range``, in which the perturbation model is assumed to be\n accurate is calculated automatically as the minimal and maximal sample temperature points.\n Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> from tidy3d import HeatDataArray\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomHeatPerturbation", + "enum": [ + "CustomHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.", + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "Sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "LinearChargePerturbation": { + "title": "LinearChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a linear function of\nelectron and hole densities:\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of electrons densities in which perturbation model is valid.\nhole_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of holes densities in which perturbation model is valid.\nelectron_ref : NonNegativeFloat\n [units = 1/cm^3]. Electron density value at which there is no perturbation due to electrons's presence.\nhole_ref : NonNegativeFloat\n [units = 1/cm^3]. Hole density value at which there is no perturbation due to holes' presence.\nelectron_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to electron density.\nhole_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to hole density.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{electron\\_coeff} \\times (N_e - \\text{electron\\_ref})\n + \\text{hole\\_coeff} \\times (N_h - \\text{hole\\_ref}),\n\n where ``electron_coeff`` and ``hole_coeff`` are the parameter's sensitivities to electron and\n hole densities, while ``electron_ref`` and ``hole_ref`` are reference electron and hole density\n values. Ranges of electron and hole densities in which such\n a model is deemed accurate may be provided as fields ``electron_range`` and ``hole_range``\n (default: ``[0, inf]`` each). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``electron_range`` x ``hole_range`` due to\n perturbations and raise a warning if this check fails. A warning is also issued if\n the perturbation model is evaluated outside of ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearChargePerturbation", + "enum": [ + "LinearChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "electron_ref": { + "title": "Reference Electron Density", + "description": "Electron density value at which there is no perturbation due to electrons's presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "hole_ref": { + "title": "Reference Hole Density", + "description": "Hole density value at which there is no perturbation due to holes' presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "electron_coeff": { + "title": "Sensitivity to Electron Density", + "description": "Sensitivity (derivative) of perturbation with respect to electron density.", + "units": "cm^3", + "type": "number" + }, + "hole_coeff": { + "title": "Sensitivity to Hole Density", + "description": "Sensitivity (derivative) of perturbation with respect to hole density.", + "units": "cm^3", + "type": "number" + } + }, + "required": [ + "electron_ref", + "hole_ref", + "electron_coeff", + "hole_coeff" + ], + "additionalProperties": false + }, + "CustomChargePerturbation": { + "title": "CustomChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a custom function of\nelectron and hole densities defined as a two-dimensional array of perturbation values at sample\nelectron and hole density points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nhole_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nperturbation_values : ChargeDataArray\n 2D array (vs electron and hole densities) of sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\nNotes\n-----\n\n The linear interpolation is used to calculate perturbation\n values between sample points. For electron and hole density values outside of the provided\n sample region the perturbation value is extrapolated as a constant.\n The electron and hole density ranges, ``electron_range`` and ``hole_range``, in which\n the perturbation model is assumed to be accurate is calculated automatically as the minimal and\n maximal density values provided in ``perturbation_values``. Wherever is applied, Tidy3D will\n check that the parameter's value does not go out of its physical bounds within\n ``electron_range`` x ``hole_range`` due to perturbations and raise a warning if this check\n fails. A warning is also issued if the perturbation model is evaluated outside of\n ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> from tidy3d import ChargeDataArray\n>>> perturbation_data = ChargeDataArray(\n... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],\n... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),\n... )\n>>> charge_perturb = CustomChargePerturbation(\n... perturbation_values=perturbation_data,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomChargePerturbation", + "enum": [ + "CustomChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "2D array (vs electron and hole densities) of sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "ParameterPerturbation": { + "title": "ParameterPerturbation", + "description": "Stores information about parameter perturbations due to different physical effect. If both\nheat and charge perturbation models are included their effects are superimposed.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nheat : Union[LinearHeatPerturbation, CustomHeatPerturbation] = None\n Heat perturbation to apply.\ncharge : Union[LinearChargePerturbation, CustomChargePerturbation] = None\n Charge perturbation to apply.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, CustomHeatPerturbation, HeatDataArray\n>>>\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )\n>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "heat": { + "title": "Heat Perturbation", + "description": "Heat perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearHeatPerturbation": "#/definitions/LinearHeatPerturbation", + "CustomHeatPerturbation": "#/definitions/CustomHeatPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearHeatPerturbation" + }, + { + "$ref": "#/definitions/CustomHeatPerturbation" + } + ] + }, + "charge": { + "title": "Charge Perturbation", + "description": "Charge perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearChargePerturbation": "#/definitions/LinearChargePerturbation", + "CustomChargePerturbation": "#/definitions/CustomChargePerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearChargePerturbation" + }, + { + "$ref": "#/definitions/CustomChargePerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "ParameterPerturbation", + "enum": [ + "ParameterPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityPerturbation": { + "title": "PermittivityPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\npermittivity and conductivity.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_eps : Optional[ParameterPerturbation] = None\n Perturbation model for permittivity.\ndelta_sigma : Optional[ParameterPerturbation] = None\n Perturbation model for conductivity.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, PermittivityPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> delta_eps = ParameterPerturbation(heat=heat_perturb)\n>>> delta_sigma = ParameterPerturbation(charge=charge_perturb)\n>>> permittivity_pb = PermittivityPerturbation(delta_eps=delta_eps, delta_sigma=delta_sigma)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_eps": { + "title": "Permittivity Perturbation", + "description": "Perturbation model for permittivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_sigma": { + "title": "Conductivity Perturbation", + "description": "Perturbation model for conductivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PermittivityPerturbation", + "enum": [ + "PermittivityPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IndexPerturbation": { + "title": "IndexPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\nrefractive index, n and k.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_n : Optional[ParameterPerturbation] = None\n Perturbation of the real part of refractive index.\ndelta_k : Optional[ParameterPerturbation] = None\n Perturbation of the imaginary part of refractive index.\nfreq : NonNegativeFloat\n [units = Hz]. Frequency to evaluate permittivity at (Hz).\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, IndexPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> dn_pb = ParameterPerturbation(heat=heat_perturb)\n>>> dk_pb = ParameterPerturbation(charge=charge_perturb)\n>>> index_pb = IndexPerturbation(delta_n=dn_pb, delta_k=dk_pb, freq=C_0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_n": { + "title": "Refractive Index Perturbation", + "description": "Perturbation of the real part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_k": { + "title": "Exctinction Coefficient Perturbation", + "description": "Perturbation of the imaginary part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "freq": { + "title": "Frequency", + "description": "Frequency to evaluate permittivity at (Hz).", + "units": "Hz", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "IndexPerturbation", + "enum": [ + "IndexPerturbation" + ], + "type": "string" + } + }, + "required": [ + "freq" + ], + "additionalProperties": false + }, + "PerturbationMedium": { + "title": "PerturbationMedium", + "description": "Dispersionless medium with perturbations. Perturbation model can be defined either directly\nthrough providing ``permittivity_perturbation`` and ``conductivity_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\npermittivity_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. List of heat and/or charge perturbations to permittivity.\nconductivity_perturbation : Optional[ParameterPerturbation] = None\n [units = S/um]. List of heat and/or charge perturbations to permittivity.\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> dielectric = PerturbationMedium(\n... permittivity=4.0,\n... permittivity_perturbation=ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... ),\n... name='my_medium',\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationMedium", + "enum": [ + "PerturbationMedium" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "permittivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "conductivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "S/um", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + }, + "additionalProperties": false + }, + "PerturbationPoleResidue": { + "title": "PerturbationPoleResidue", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationPoleResidue", + "enum": [ + "PerturbationPoleResidue" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + }, + "eps_inf_perturbation": { + "title": "Perturbation of Epsilon at Infinity", + "description": "Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "poles_perturbation": { + "title": "Perturbations of Poles", + "description": "Perturbations to poles of the model.", + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "$ref": "#/definitions/ParameterPerturbation" + }, + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + } + }, + "additionalProperties": false + }, + "Medium2D": { + "title": "Medium2D", + "description": "2D diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nss : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.\ntt : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> medium2d = Medium2D(ss=drude_medium, tt=drude_medium)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium2D", + "enum": [ + "Medium2D" + ], + "type": "string" + }, + "ss": { + "title": "SS Component", + "description": "Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + }, + "tt": { + "title": "TT Component", + "description": "Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + } + }, + "required": [ + "ss", + "tt" + ], + "additionalProperties": false + }, + "AnisotropicMediumFromMedium2D": { + "title": "AnisotropicMediumFromMedium2D", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMediumFromMedium2D", + "enum": [ + "AnisotropicMediumFromMedium2D" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "ChargeConductorMedium": { + "title": "ChargeConductorMedium", + "description": "Conductor medium for conduction simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : PositiveFloat\n [units = S/um]. Electric conductivity of material in units of S/um.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeConductorMedium(conductivity=3)\n\nNote\n----\n A relative permittivity will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeConductorMedium", + "enum": [ + "ChargeConductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "conductivity": { + "title": "Electric conductivity", + "description": "Electric conductivity of material in units of S/um.", + "units": "S/um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "ChargeInsulatorMedium": { + "title": "ChargeInsulatorMedium", + "description": "Insulating medium. Conduction simulations will not solve for electric\npotential in a structure that has a medium with this 'charge'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeInsulatorMedium()\n>>> solid2 = td.ChargeInsulatorMedium(permittivity=1.1)\n\nNote\n----\n A relative permittivity :math:`\\varepsilon` will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeInsulatorMedium", + "enum": [ + "ChargeInsulatorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + } + }, + "additionalProperties": false + }, + "CaugheyThomasMobility": { + "title": "CaugheyThomasMobility", + "description": "The Caughey-Thomas temperature-dependent carrier mobility model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu_min : PositiveFloat\n Minimum electron mobility at reference temperature (300K) in cm^2/V-s. \nmu : PositiveFloat\n Reference mobility at reference temperature (300K) in cm^2/V-s\nexp_2 : float\n exp_N : PositiveFloat\n Exponent for doping dependence of mobility at reference temperature (300K).\nref_N : PositiveFloat\n Reference doping at reference temperature (300K) in #/cm^3.\nexp_1 : float\n Exponent of thermal dependence of minimum mobility.\nexp_3 : float\n Exponent of thermal dependence of reference doping.\nexp_4 : float\n Exponent of thermal dependence of the doping exponent effect.\n\nNotes\n-----\n The general form of the Caughey-Thomas mobility model [1]_ is of the form:\n\n .. math::\n\n \\mu_0 = \\frac{\\mu_{max} - \\mu_{min}}{1 + \\left(N/N_{ref}\\right)^z} + \\mu_{min}\n\nwhere :math:`\\mu_0` represents the low-field mobility and :math:`N` is the total doping (acceptors + donors).\n:math:`\\mu_{max}`, :math:`\\mu_{min}`, :math:`z`, and :math:`N_{ref}` are temperature dependent,\nthe dependence being of the form\n\n.. math::\n\n \\phi = \\phi_{ref} \\left( \\frac{T}{T_{ref}}\\right)^\\alpha\n\nand :math:`T_{ref}` is taken to be 300K.\n\nThe complete form (with temperature effects) for the low-field mobility can be written as\n\n.. math::\n\n \\mu_0 = \\frac{\\mu_{max}(\\frac{T}{T_{ref}})^{\\alpha_2} - \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}}{1 + \\left(N/N_{ref}(\\frac{T}{T_{ref}})^{\\alpha_3}\\right)^{\\alpha_N(\\frac{T}{T_{ref}})^{\\alpha_4}}} + \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}\n\nThe following table maps the symbols used in the equations above with the names used in the code:\n\n.. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`\\mu_{min}`\n - ``mu_min``\n - Minimum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\mu_{max}`\n - ``mu_n``\n - Maximum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\alpha_1`\n - ``exp_1``\n - Exponent for temperature dependence of the minimum mobility coefficient\n * - :math:`\\alpha_2`\n - ``exp_2``\n - Exponent for temperature dependence of the maximum mobility coefficient\n * - :math:`\\alpha_N`\n - ``exp_N``\n - Exponent for doping dependence.\n * - :math:`\\alpha_4`\n - ``exp_4``\n - Exponent for the temperature dependence of the exponent :math:`\\alpha_N`\n * - :math:`N_{ref}`\n - ``ref_N``,\n - Reference doping parameter\n\n\n.. [1] M. Caughey and R.E. Thomas. Carrier mobilities in silicon empirically related to doping\n and field. Proceedings of the IEEE, 55(12):2192\u20132193, December 1967\n\nExample\n-------\n >>> import tidy3d as td\n >>> mobility_Si_n = td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n >>> mobility_Si_p = td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n\n\nWarning\n-------\nThere are some current limitations of this model:\n\n- High electric field effects not yet supported.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu_min": { + "title": "$\\mu_{min}$ Minimum electron mobility", + "description": "Minimum electron mobility at reference temperature (300K) in cm^2/V-s. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "mu": { + "title": "Reference mobility", + "description": "Reference mobility at reference temperature (300K) in cm^2/V-s", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_2": { + "title": "Exponent for temperature dependent behavior of reference mobility", + "type": "number" + }, + "exp_N": { + "title": "Exponent for doping dependence of mobility.", + "description": "Exponent for doping dependence of mobility at reference temperature (300K).", + "exclusiveMinimum": 0, + "type": "number" + }, + "ref_N": { + "title": "Reference doping", + "description": "Reference doping at reference temperature (300K) in #/cm^3.", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_1": { + "title": "Exponent of thermal dependence of minimum mobility.", + "description": "Exponent of thermal dependence of minimum mobility.", + "type": "number" + }, + "exp_3": { + "title": "Exponent of thermal dependence of reference doping.", + "description": "Exponent of thermal dependence of reference doping.", + "type": "number" + }, + "exp_4": { + "title": "Exponent of thermal dependence of the doping exponent effect.", + "description": "Exponent of thermal dependence of the doping exponent effect.", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CaugheyThomasMobility", + "enum": [ + "CaugheyThomasMobility" + ], + "type": "string" + } + }, + "required": [ + "mu_min", + "mu", + "exp_2", + "exp_N", + "ref_N", + "exp_1", + "exp_3", + "exp_4" + ], + "additionalProperties": false + }, + "ConstantMobilityModel": { + "title": "ConstantMobilityModel", + "description": "Constant mobility model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu : NonNegativeFloat\n [units = cm\u00b2/V-s]. Mobility\n\nExample\n-------\n>>> import tidy3d as td\n>>> mobility_model = td.ConstantMobilityModel(mu=1500)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu": { + "title": "Mobility", + "description": "Mobility", + "units": "cm\u00b2/V-s", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ConstantMobilityModel", + "enum": [ + "ConstantMobilityModel" + ], + "type": "string" + } + }, + "required": [ + "mu" + ], + "additionalProperties": false + }, + "AugerRecombination": { + "title": "AugerRecombination", + "description": "Parameters for the Auger recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nc_n : PositiveFloat\n Constant for electrons in cm^6/s\nc_p : PositiveFloat\n Constant for holes in cm^6/s\n\nNotes\n-----\n\n The Auger recombination rate ``R_A`` is primarily defined by the electrons and holes Auger recombination\n coefficients, :math:`C_n` and :math:`C_p`, respectively.\n\n .. math::\n\n R_A = \\left( C_n n + C_p p \\right) \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32,\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "c_n": { + "title": "Constant for electrons", + "description": "Constant for electrons in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "c_p": { + "title": "Constant for holes", + "description": "Constant for holes in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AugerRecombination", + "enum": [ + "AugerRecombination" + ], + "type": "string" + } + }, + "required": [ + "c_n", + "c_p" + ], + "additionalProperties": false + }, + "RadiativeRecombination": { + "title": "RadiativeRecombination", + "description": "Defines the parameters for the radiative recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr_const : float\n Radiation constant in cm^3/s\n\nNotes\n-----\n\n This is a direct recombination model primarily defined by a radiative recombination coefficient :math:`R_{\\text{rad}}`.\n\n .. math::\n\n R_{\\text{rad}} = C \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r_const": { + "title": "Radiation constant in cm^3/s", + "description": "Radiation constant in cm^3/s", + "type": "number" + }, + "type": { + "title": "Type", + "default": "RadiativeRecombination", + "enum": [ + "RadiativeRecombination" + ], + "type": "string" + } + }, + "required": [ + "r_const" + ], + "additionalProperties": false + }, + "FossumCarrierLifetime": { + "title": "FossumCarrierLifetime", + "description": "Parameters for the Fossum carrier lifetime model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_300 : PositiveFloat\n [units = sec]. Carrier lifetime at 300K\nalpha_T : float\n Exponent for thermal dependence\nN0 : PositiveFloat\n [units = 1/cm^3]. Reference concentration\nA : float\n Constant A\nB : float\n Constant B\nC : float\n Constant C\nalpha : float\n Exponent constant\n\nNotes\n-----\n\n This model expresses the carrier lifetime as a function of the temperature and doping concentration.\n\n .. math::\n\n \\tau = \\frac{\\tau_{300} \\left( T/300 \\right)^\\alpha_T}{A + B (N/N_0) + C (N/N_0)^\\alpha}\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.FossumCarrierLifetime(\n ... tau_300=3.3e-6,\n ... alpha_T=-0.5,\n ... N0=7.1e15,\n ... A=1,\n ... B=0,\n ... C=1,\n ... alpha=1\n ... )\n\nReferences\n----------\n\n Fossum, J. G., and D. S. Lee. \"A physical model for the dependence of carrier lifetime on doping density in nondegenerate silicon.\" Solid-State Electronics 25.8 (1982): 741-747.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_300": { + "title": "Tau at 300K", + "description": "Carrier lifetime at 300K", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "alpha_T": { + "title": "Exponent for thermal dependence", + "description": "Exponent for thermal dependence", + "type": "number" + }, + "N0": { + "title": "Reference concentration", + "description": "Reference concentration", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "A": { + "title": "Constant A", + "description": "Constant A", + "type": "number" + }, + "B": { + "title": "Constant B", + "description": "Constant B", + "type": "number" + }, + "C": { + "title": "Constant C", + "description": "Constant C", + "type": "number" + }, + "alpha": { + "title": "Exponent constant", + "description": "Exponent constant", + "type": "number" + }, + "type": { + "title": "Type", + "default": "FossumCarrierLifetime", + "enum": [ + "FossumCarrierLifetime" + ], + "type": "string" + } + }, + "required": [ + "tau_300", + "alpha_T", + "N0", + "A", + "B", + "C", + "alpha" + ], + "additionalProperties": false + }, + "ShockleyReedHallRecombination": { + "title": "ShockleyReedHallRecombination", + "description": "Defines the parameters for the Shockley-Reed-Hall (SRH) recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_n : Union[PositiveFloat, FossumCarrierLifetime]\n Electron lifetime\ntau_p : Union[PositiveFloat, FossumCarrierLifetime]\n [units = sec]. Hole lifetime\n\nNotes\n-----\n\n The recombination rate parameter from this model is defined from [1]_ as follows:\n\n .. math::\n\n R_{SRH} = \\frac{n p - n_0 p_0}{\\tau_p \\left(n + \\sqrt{n_0 p_0}\\right) + \\tau_n \\left(p + \\sqrt{n_0 p_0}\\right)}.\n\n Note that the electron and holes densities are defined within the :class:`SemiconductorMedium`. The electron\n lifetime :math:`\\tau_n` and hole lifetimes :math:`\\tau_p` need to be defined.\n\n\n .. [1] Schenk. A model for the field and temperature dependence of shockley-read-hall\n lifetimes in silicon. Solid-State Electronics, 35:1585\u20131596, 1992.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6,\n ... )\n\nNote\n----\nImportant considerations when using this model:\n\n- Currently, lifetimes are considered constant (not dependent on temperature or doping).\n- This model represents mid-gap traps Shockley-Reed-Hall recombination.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_n": { + "title": "Electron lifetime", + "description": "Electron lifetime", + "union": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "tau_p": { + "title": "Hole lifetime", + "description": "Hole lifetime", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "type": { + "title": "Type", + "default": "ShockleyReedHallRecombination", + "enum": [ + "ShockleyReedHallRecombination" + ], + "type": "string" + } + }, + "required": [ + "tau_n", + "tau_p" + ], + "additionalProperties": false + }, + "SlotboomBandGapNarrowing": { + "title": "SlotboomBandGapNarrowing", + "description": "Parameters for the Slotboom model for band-gap narrowing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nv1 : PositiveFloat\n [units = V]. $V_{1,bgn}$ parameter\nn2 : PositiveFloat\n [units = 1/cm^3]. $N_{2,bgn}$ parameter\nc2 : float\n $C_{2,bgn}$ parameter\nmin_N : NonNegativeFloat\n [units = 1/cm^3]. Bandgap narrowing is applied at location where total doping is higher than 'min_N'.\n\nNotes\n------\n The Slotboom band-gap narrowing :math:`\\Delta E_G` model is discussed in [1]_ as follows:\n\n .. math::\n\n \\Delta E_G = V_{1,bgn} \\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right)\n + \\sqrt{\\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right) \\right)^2 + C_{2,bgn}} \\right)\n \\quad \\text{if} \\quad N_{tot} \\geq 10^{15} \\text{cm}^{-3},\n\n \\Delta E_G = 0 \\quad \\text{if} \\quad N_{tot} < 10^{15} \\text{cm}^{-3}.\n\n Note that :math:`N_{tot}` is the total doping as defined within a :class:`SemiconductorMedium`.\n\n Example\n -------\n >>> import tidy3d as td\n >>> default_Si = td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... )\n\n .. [1] 'UNIFIED APPARENT BANDGAP NARROWING IN n- AND p-TYPE SILICON' Solid-State Electronics Vol. 35, No. 2, pp. 125-129, 1992", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "v1": { + "title": "$V_{1,bgn}$ parameter", + "description": "$V_{1,bgn}$ parameter", + "units": "V", + "exclusiveMinimum": 0, + "type": "number" + }, + "n2": { + "title": "$N_{2,bgn}$ parameter", + "description": "$N_{2,bgn}$ parameter", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "c2": { + "title": "$C_{2,bgn}$ parameter", + "description": "$C_{2,bgn}$ parameter", + "type": "number" + }, + "min_N": { + "title": "Minimum total doping", + "description": "Bandgap narrowing is applied at location where total doping is higher than 'min_N'.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "SlotboomBandGapNarrowing", + "enum": [ + "SlotboomBandGapNarrowing" + ], + "type": "string" + } + }, + "required": [ + "v1", + "n2", + "c2", + "min_N" + ], + "additionalProperties": false + }, + "ConstantDoping": { + "title": "ConstantDoping", + "description": "Sets constant doping :math:`N` in the specified box with a :parameter`size` and :parameter:`concentration`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nconcentration : NonNegativeFloat = 0\n [units = 1/cm^3]. Doping concentration density in #/cm^3.\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> constant_box1 = td.ConstantDoping(center=(0, 0, 0), size=(2, 2, 2), concentration=1e18)\n>>> constant_box2 = td.ConstantDoping.from_bounds(rmin=box_coords[0], rmax=box_coords[1], concentration=1e18)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConstantDoping", + "enum": [ + "ConstantDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "concentration": { + "title": "Doping concentration density.", + "description": "Doping concentration density in #/cm^3.", + "default": 0, + "units": "1/cm^3", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "GaussianDoping": { + "title": "GaussianDoping", + "description": "Sets a gaussian doping in the specified box.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nref_con : PositiveFloat\n Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.\nconcentration : PositiveFloat\n The concentration at the center of the box.\nwidth : PositiveFloat\n Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. \nsource : str = xmin\n Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nNotes\n-----\nThe Gaussian doping concentration :math:`N` is defined in the following manner:\n\n- :math:`N=N_{\\text{max}}` at locations more than :math:``width`` um away from the sides of the box.\n- :math:`N=N_{\\text{ref}}` at location on the box sides.\n- a Gaussian variation between :math:`N_{\\text{max}}` and :math:`N_{\\text{ref}}` at locations less than ``width``\num away from the sides.\n\nBy definition, all sides of the box will have concentration :math:`N_{\\text{ref}}` (except the side specified\nas source) and the center of the box (``width`` away from the box sides) will have a concentration\n:math:`N_{\\text{max}}`.\n\n.. math::\n\n N = \\{N_{\\text{max}}\\} \\exp \\left[\n - \\ln \\left( \\frac{\\{N_{\\text{max}}\\}}{\\{N_{\\text{ref}}\\}} \\right)\n \\left( \\frac{(x|y|z) - \\{(x|y|z)_{\\text{box}}\\}}{\\text{width}} \\right)^2\n \\right]\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> gaussian_box1 = td.GaussianDoping(\n... center=(0, 0, 0),\n... size=(2, 2, 2),\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )\n>>> gaussian_box2 = td.GaussianDoping.from_bounds(\n... rmin=box_coords[0],\n... rmax=box_coords[1],\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GaussianDoping", + "enum": [ + "GaussianDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "ref_con": { + "title": "Reference concentration.", + "description": "Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concentration": { + "title": "Concentration", + "description": "The concentration at the center of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "width": { + "title": "Width of the gaussian.", + "description": "Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "source": { + "title": "Source face", + "description": "Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']", + "default": "xmin", + "type": "string" + } + }, + "required": [ + "size", + "ref_con", + "concentration", + "width" + ], + "additionalProperties": false + }, + "SemiconductorMedium": { + "title": "SemiconductorMedium", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "SemiconductorMedium", + "enum": [ + "SemiconductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "N_c": { + "title": "Effective density of electron states", + "description": "$N_c$ Effective density of states in the conduction band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "N_v": { + "title": "Effective density of hole states", + "description": "$N_v$ Effective density of states in the valence band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "E_g": { + "title": "Band-gap energy", + "description": "Band-gap energy", + "units": "eV", + "exclusiveMinimum": 0, + "type": "number" + }, + "mobility_n": { + "title": "Mobility model for electrons", + "description": "Mobility model for electrons", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "mobility_p": { + "title": "Mobility model for holes", + "description": "Mobility model for holes", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "R": { + "title": "Generation-Recombination models", + "description": "Array containing the R models to be applied to the material.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/AugerRecombination" + }, + { + "$ref": "#/definitions/RadiativeRecombination" + }, + { + "$ref": "#/definitions/ShockleyReedHallRecombination" + } + ] + } + }, + "delta_E_g": { + "title": "$\\Delta E_g$ Bandgap narrowing model.", + "description": "Bandgap narrowing model.", + "allOf": [ + { + "$ref": "#/definitions/SlotboomBandGapNarrowing" + } + ] + }, + "N_a": { + "title": "Doping: Acceptor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + }, + "N_d": { + "title": "Doping: Donor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + } + }, + "required": [ + "N_c", + "N_v", + "E_g", + "mobility_n", + "mobility_p" + ], + "additionalProperties": false + }, + "MultiPhysicsMedium": { + "title": "MultiPhysicsMedium", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Medium name", + "type": "string" + }, + "optical": { + "title": "Optical properties", + "description": "Specifies optical properties.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "heat": { + "title": "Heat properties", + "description": "Specifies properties for Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "charge": { + "title": "Charge properties", + "description": "Specifies properties for Charge simulations.", + "anyOf": [ + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "MultiPhysicsMedium", + "enum": [ + "MultiPhysicsMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Box": { + "title": "Box", + "description": "Rectangular prism.\n Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\n\nExample\n-------\n>>> b = Box(center=(1,2,3), size=(2,2,2))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Box", + "enum": [ + "Box" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "Sphere": { + "title": "Sphere", + "description": "Spherical geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nradius : NonNegativeFloat\n [units = um]. Radius of geometry.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\n\nExample\n-------\n>>> b = Sphere(center=(1,2,3), radius=2)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Sphere", + "enum": [ + "Sphere" + ], + "type": "string" + }, + "radius": { + "title": "Radius", + "description": "Radius of geometry.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "radius" + ], + "additionalProperties": false + }, + "Cylinder": { + "title": "Cylinder", + "description": "Cylindrical geometry with optional sidewall angle along axis\ndirection. When ``sidewall_angle`` is nonzero, the shape is a\nconical frustum or a cone.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> c = Cylinder(center=(1,2,3), radius=2, length=5, axis=2)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../../notebooks/THzDemultiplexerFilter.html>`_\n* `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Cylinder", + "enum": [ + "Cylinder" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([(0,0), (1,0), (1,1)])\n>>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolySlab", + "enum": [ + "PolySlab" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])\n>>> faces = np.array([[1, 2, 3], [0, 3, 2], [0, 1, 3], [0, 2, 1]])\n>>> stl_geom = TriangleMesh.from_vertices_faces(vertices, faces)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangleMesh", + "enum": [ + "TriangleMesh" + ], + "type": "string" + }, + "mesh_dataset": { + "title": "Surface mesh data", + "description": "Surface mesh data.", + "allOf": [ + { + "$ref": "#/definitions/TriangleMeshDataset" + } + ] + } + }, + "required": [ + "mesh_dataset" + ], + "additionalProperties": false + }, + "GeometryGroup": { + "title": "GeometryGroup", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GeometryGroup", + "enum": [ + "GeometryGroup" + ], + "type": "string" + }, + "geometries": { + "title": "Geometries", + "description": "Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + } + }, + "required": [ + "geometries" + ], + "additionalProperties": false + }, + "ClipOperation": { + "title": "ClipOperation", + "description": "Class representing the result of a set operation between geometries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\noperation : Literal['union', 'intersection', 'difference', 'symmetric_difference']\n Operation to be performed between geometries.\ngeometry_a : ForwardRef('annotate_type(GeometryType)')\n First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.\ngeometry_b : ForwardRef('annotate_type(GeometryType)')\n Second operand for the set operation. It can also be any geometry type.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ClipOperation", + "enum": [ + "ClipOperation" + ], + "type": "string" + }, + "operation": { + "title": "Operation Type", + "description": "Operation to be performed between geometries.", + "enum": [ + "union", + "intersection", + "difference", + "symmetric_difference" + ], + "type": "string" + }, + "geometry_a": { + "title": "Geometry A", + "description": "First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "geometry_b": { + "title": "Geometry B", + "description": "Second operand for the set operation. It can also be any geometry type.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + }, + "required": [ + "operation", + "geometry_a", + "geometry_b" + ], + "additionalProperties": false + }, + "Transformed": { + "title": "Transformed", + "description": "Class representing a transformed geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : ForwardRef('annotate_type(GeometryType)')\n Base geometry to be transformed.\ntransform : ArrayLike[dtype=float, ndim=2, shape=(4, 4)] = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]\n Transform matrix applied to the base geometry.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Transformed", + "enum": [ + "Transformed" + ], + "type": "string" + }, + "geometry": { + "title": "Geometry", + "description": "Base geometry to be transformed.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "transform": { + "title": "Transform", + "description": "Transform matrix applied to the base geometry.", + "default": [ + [ + 1.0, + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "type": "ArrayLike" + } + }, + "required": [ + "geometry" + ], + "additionalProperties": false + }, + "Structure": { + "title": "Structure", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, + "type": { + "title": "Type", + "default": "Structure", + "enum": [ + "Structure" + ], + "type": "string" + }, + "medium": { + "title": "Medium", + "description": "Defines the electromagnetic properties of the structure's medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + } + }, + "required": [ + "geometry", + "medium" + ], + "additionalProperties": false + }, + "HeatSource": { + "title": "HeatSource", + "description": "Adds a volumetric heat source (heat sink if negative values\nare provided) to specific structures in the scene.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = HeatSource(rate=1, structures=[\"box\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatSource", + "enum": [ + "HeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "HeatFromElectricSource": { + "title": "HeatFromElectricSource", + "description": "Volumetric heat source generated from an electric simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\n\nNotes\n-----\n\n If a :class`HeatFromElectricSource` is specified as a source, appropriate boundary\n conditions for an electric simulation must be provided, since such a simulation\n will be executed before the heat simulation can run.\n\nExample\n-------\n>>> heat_source = HeatFromElectricSource()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatFromElectricSource", + "enum": [ + "HeatFromElectricSource" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UniformHeatSource": { + "title": "UniformHeatSource", + "description": "Volumetric heat source. This class is deprecated. You can use\n'HeatSource' instead.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = UniformHeatSource(rate=1, structures=[\"box\"]) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "UniformHeatSource", + "enum": [ + "UniformHeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "StructureBoundary": { + "title": "StructureBoundary", + "description": "Placement of boundary conditions on the structure's boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\n\nExample\n-------\n>>> bc_placement = StructureBoundary(structure=\"box\")", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureBoundary", + "enum": [ + "StructureBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "StructureStructureInterface": { + "title": "StructureStructureInterface", + "description": "Placement of boundary conditions between two structures.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructures : Tuple[str, str]\n Names of two structures.\n\nExample\n-------\n>>> bc_placement = StructureStructureInterface(structures=[\"box\", \"sphere\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureStructureInterface", + "enum": [ + "StructureStructureInterface" + ], + "type": "string" + }, + "structures": { + "title": "Structures", + "description": "Names of two structures.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "structures" + ], + "additionalProperties": false + }, + "MediumMediumInterface": { + "title": "MediumMediumInterface", + "description": "Placement of boundary conditions between two mediums.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmediums : Tuple[str, str]\n Names of two mediums.\n\nExample\n-------\n>>> bc_placement = MediumMediumInterface(mediums=[\"dieletric\", \"metal\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "MediumMediumInterface", + "enum": [ + "MediumMediumInterface" + ], + "type": "string" + }, + "mediums": { + "title": "Mediums", + "description": "Names of two mediums.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "mediums" + ], + "additionalProperties": false + }, + "SimulationBoundary": { + "title": "SimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = SimulationBoundary(surfaces=[\"x-\", \"x+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SimulationBoundary", + "enum": [ + "SimulationBoundary" + ], + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "additionalProperties": false + }, + "StructureSimulationBoundary": { + "title": "StructureSimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary covered by the structure.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = StructureSimulationBoundary(structure=\"box\", surfaces=[\"y-\", \"y+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureSimulationBoundary", + "enum": [ + "StructureSimulationBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "TemperatureBC": { + "title": "TemperatureBC", + "description": "Constant temperature thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat\n [units = K]. Temperature value in units of K.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.TemperatureBC(temperature=300)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureBC", + "enum": [ + "TemperatureBC" + ], + "type": "string" + }, + "temperature": { + "title": "Temperature", + "description": "Temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "temperature" + ], + "additionalProperties": false + }, + "HeatFluxBC": { + "title": "HeatFluxBC", + "description": "Constant flux thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nflux : float\n [units = W/um^2]. Heat flux value in units of W/um^2.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.HeatFluxBC(flux=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatFluxBC", + "enum": [ + "HeatFluxBC" + ], + "type": "string" + }, + "flux": { + "title": "Heat Flux", + "description": "Heat flux value in units of W/um^2.", + "units": "W/um^2", + "type": "number" + } + }, + "required": [ + "flux" + ], + "additionalProperties": false + }, + "ConvectionBC": { + "title": "ConvectionBC", + "description": "Convective thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nambient_temperature : PositiveFloat\n [units = K]. Ambient temperature value in units of K.\ntransfer_coeff : NonNegativeFloat\n [units = W/(um^2*K)]. Heat flux value in units of W/(um^2*K).\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.ConvectionBC(ambient_temperature=300, transfer_coeff=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConvectionBC", + "enum": [ + "ConvectionBC" + ], + "type": "string" + }, + "ambient_temperature": { + "title": "Ambient Temperature", + "description": "Ambient temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "transfer_coeff": { + "title": "Heat Transfer Coefficient", + "description": "Heat flux value in units of W/(um^2*K).", + "units": "W/(um^2*K)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "ambient_temperature", + "transfer_coeff" + ], + "additionalProperties": false + }, + "DCVoltageSource": { + "title": "DCVoltageSource", + "description": "DC voltage source in volts.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n voltage : ArrayLike[dtype=float, ndim=1]\n [units = V]. DC voltage usually used as source in 'VoltageBC' boundary conditions.\nunits : Literal['V'] = V\n \nNotes\n-----\n\n This voltage refers to potential above the equivalent simulation ground. Currently, electrical ports\n are not defined.\n\nExamples\n--------\n>>> import tidy3d as td\n>>> voltages = [-0.5, 0, 1, 2, 3, 4]\n>>> voltage_source = td.DCVoltageSource(voltage=voltages)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "voltage": { + "title": "Voltage", + "description": "DC voltage usually used as source in 'VoltageBC' boundary conditions.", + "units": "V", + "type": "ArrayLike" + }, + "units": { + "title": "Units", + "default": "V", + "enum": [ + "V" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCVoltageSource", + "enum": [ + "DCVoltageSource" + ], + "type": "string" + } + }, + "required": [ + "voltage" + ], + "additionalProperties": false + }, + "VoltageBC": { + "title": "VoltageBC", + "description": "Constant electric potential (voltage) :math:`= \\text{V}` boundary condition.\nSets a potential at the specified boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCVoltageSource\n [units = V]. Electric potential to be applied at the specified boundary.\n\nNotes\n-----\n\n In charge simulations it also accepts an array of voltages.\n In this case, a solution for each of these voltages will\n be computed.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_source = td.DCVoltageSource(voltage=1)\n>>> voltage_bc = td.VoltageBC(source=voltage_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VoltageBC", + "enum": [ + "VoltageBC" + ], + "type": "string" + }, + "source": { + "title": "Voltage", + "description": "Electric potential to be applied at the specified boundary.", + "units": "V", + "allOf": [ + { + "$ref": "#/definitions/DCVoltageSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "DCCurrentSource": { + "title": "DCCurrentSource", + "description": "DC current source in amperes.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n current : FiniteFloat\n [units = A]. DC current usually used as source in 'CurrentBC' boundary conditions.\nunits : Literal['A'] = A\n \nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=0.4)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "current": { + "title": "Current", + "description": "DC current usually used as source in 'CurrentBC' boundary conditions.", + "units": "A", + "type": "number" + }, + "units": { + "title": "Units", + "default": "A", + "enum": [ + "A" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCCurrentSource", + "enum": [ + "DCCurrentSource" + ], + "type": "string" + } + }, + "required": [ + "current" + ], + "additionalProperties": false + }, + "CurrentBC": { + "title": "CurrentBC", + "description": "Current boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCCurrentSource\n [units = A/um^2]. A current source\n\nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=1)\n>>> current_bc = CurrentBC(source=current_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CurrentBC", + "enum": [ + "CurrentBC" + ], + "type": "string" + }, + "source": { + "title": "Current Source", + "description": "A current source", + "units": "A/um^2", + "allOf": [ + { + "$ref": "#/definitions/DCCurrentSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "InsulatingBC": { + "title": "InsulatingBC", + "description": "Insulation boundary condition.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNotes\n-----\n\n Ensures the electric potential to the normal :math:`\\nabla \\psi \\cdot \\mathbf{n} = 0` as well as the\n surface recombination current density :math:`J_s = \\mathbf{J} \\cdot \\mathbf{n} = 0` are set to zero where\n the current density is :math:`\\mathbf{J_n}` and the normal vector is :math:`\\mathbf{n}`\n\nExample\n-------\n>>> bc = InsulatingBC()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "InsulatingBC", + "enum": [ + "InsulatingBC" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "HeatChargeBoundarySpec": { + "title": "HeatChargeBoundarySpec", + "description": "Heat-Charge boundary conditions specification.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc_v1 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),\n... placement=td.StructureBoundary(structure=\"contact_left\"),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatChargeBoundarySpec", + "enum": [ + "HeatChargeBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "HeatBoundarySpec": { + "title": "HeatBoundarySpec", + "description": "Heat BC specification. DEPRECIATED.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nWarning\n-------\n Included backward-compatibility only.\n\nExample\n--------\n>>> import tidy3d as td\n>>> bc_spec = td.HeatBoundarySpec(\n... placement=td.SimulationBoundary(),\n... condition=td.ConvectionBC(ambient_temperature=300, transfer_coeff=1),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatBoundarySpec", + "enum": [ + "HeatBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "TemperatureMonitor": { + "title": "TemperatureMonitor", + "description": "Temperature monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\ninterval : PositiveInt = 1\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureMonitor", + "enum": [ + "TemperatureMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + }, + "interval": { + "title": "Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyPotentialMonitor": { + "title": "SteadyPotentialMonitor", + "description": "Electric potential (:math:`\\psi`) monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyPotentialMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyPotentialMonitor", + "enum": [ + "SteadyPotentialMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyFreeCarrierMonitor": { + "title": "SteadyFreeCarrierMonitor", + "description": "Free-carrier monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyFreeCarrierMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyFreeCarrierMonitor", + "enum": [ + "SteadyFreeCarrierMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyEnergyBandMonitor": { + "title": "SteadyEnergyBandMonitor", + "description": "Energy bands monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> energy_monitor_z0 = td.SteadyEnergyBandMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"bands_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyEnergyBandMonitor", + "enum": [ + "SteadyEnergyBandMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyElectricFieldMonitor": { + "title": "SteadyElectricFieldMonitor", + "description": "Electric field monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> electric_field_monitor_z0 = td.SteadyElectricFieldMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"electric_field_z0\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyElectricFieldMonitor", + "enum": [ + "SteadyElectricFieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyCapacitanceMonitor": { + "title": "SteadyCapacitanceMonitor", + "description": "Capacitance monitor associated with a charge simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> capacitance_global_mnt = td.SteadyCapacitanceMonitor(\n... center=(0, 0.14, 0), size=(td.inf, td.inf, 0), name=\"capacitance_global_mnt\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyCapacitanceMonitor", + "enum": [ + "SteadyCapacitanceMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "UniformUnstructuredGrid": { + "title": "UniformUnstructuredGrid", + "description": "Uniform grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\nmin_edges_per_circumference : PositiveFloat = 15\n Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.\nmin_edges_per_side : PositiveFloat = 2\n Enforced minimum number of mesh segments per any side of an object.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.\n\nExample\n-------\n>>> heat_grid = UniformUnstructuredGrid(dl=0.1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "UniformUnstructuredGrid", + "enum": [ + "UniformUnstructuredGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_circumference": { + "title": "Minimum Edges per Circumference", + "description": "Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.", + "default": 15, + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_side": { + "title": "Minimum Edges per Side", + "description": "Enforced minimum number of mesh segments per any side of an object.", + "default": 2, + "exclusiveMinimum": 0, + "type": "number" + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GridRefinementRegion": { + "title": "GridRefinementRegion", + "description": "Refinement region for the unstructured mesh. The cell size is enforced to be constant inside the region.\nThe cell size outside of the region depends on the distance from the region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\ndl_internal : PositiveFloat\n [units = um]. Mesh cell size inside the refinement region\ntransition_thickness : NonNegativeFloat\n [units = um]. Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GridRefinementRegion", + "enum": [ + "GridRefinementRegion" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "dl_internal": { + "title": "Internal mesh cell size", + "description": "Mesh cell size inside the refinement region", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "transition_thickness": { + "title": "Interface Distance", + "description": "Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "units": "um", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "dl_internal", + "transition_thickness" + ], + "additionalProperties": false + }, + "GridRefinementLine": { + "title": "GridRefinementLine", + "description": "Refinement line for the unstructured mesh. The cell size depends on the distance from the line.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr1 : Tuple[float, float, float]\n [units = um]. Start point of the line in x, y, and z.\nr2 : Tuple[float, float, float]\n [units = um]. End point of the line in x, y, and z.\ndl_near : PositiveFloat\n [units = um]. Mesh cell size near the line\ndistance_near : NonNegativeFloat\n [units = um]. Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r1": { + "title": "Start point of the line", + "description": "Start point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "r2": { + "title": "End point of the line", + "description": "End point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "dl_near": { + "title": "Mesh cell size near the line", + "description": "Mesh cell size near the line", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_near": { + "title": "Near distance", + "description": "Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk distance", + "description": "Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "GridRefinementLine", + "enum": [ + "GridRefinementLine" + ], + "type": "string" + } + }, + "required": [ + "r1", + "r2", + "dl_near", + "distance_near", + "distance_bulk" + ], + "additionalProperties": false + }, + "DistanceUnstructuredGrid": { + "title": "DistanceUnstructuredGrid", + "description": "Adaptive grid based on distance to material interfaces. Currently not recommended for larger\nsimulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl_interface : PositiveFloat\n [units = um]. Grid size near material interfaces.\ndl_bulk : PositiveFloat\n [units = um]. Grid size away from material interfaces.\ndistance_interface : NonNegativeFloat\n [units = um]. Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.\nsampling : PositiveFloat = 100\n An internal advanced parameter that defines number of sampling points per surface when computing distance values.\nuniform_grid_mediums : Tuple[str, ...] = ()\n List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.\nmesh_refinements : Tuple[Annotated[Union[tidy3d.components.tcad.grid.GridRefinementRegion, tidy3d.components.tcad.grid.GridRefinementLine], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of regions/lines for which the mesh refinement will be applied\n\nExample\n-------\n>>> heat_grid = DistanceUnstructuredGrid(\n... dl_interface=0.1,\n... dl_bulk=1,\n... distance_interface=0.3,\n... distance_bulk=2,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "DistanceUnstructuredGrid", + "enum": [ + "DistanceUnstructuredGrid" + ], + "type": "string" + }, + "dl_interface": { + "title": "Interface Grid Size", + "description": "Grid size near material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl_bulk": { + "title": "Bulk Grid Size", + "description": "Grid size away from material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_interface": { + "title": "Interface Distance", + "description": "Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk Distance", + "description": "Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "sampling": { + "title": "Surface Sampling", + "description": "An internal advanced parameter that defines number of sampling points per surface when computing distance values.", + "default": 100, + "exclusiveMinimum": 0, + "type": "number" + }, + "uniform_grid_mediums": { + "title": "Mediums With Uniform Refinement", + "description": "List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "mesh_refinements": { + "title": "Mesh refinement structures", + "description": "List of regions/lines for which the mesh refinement will be applied", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "GridRefinementRegion": "#/definitions/GridRefinementRegion", + "GridRefinementLine": "#/definitions/GridRefinementLine" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GridRefinementRegion" + }, + { + "$ref": "#/definitions/GridRefinementLine" + } + ] + } + } + }, + "required": [ + "dl_interface", + "dl_bulk", + "distance_interface", + "distance_bulk" + ], + "additionalProperties": false + }, + "ChargeToleranceSpec": { + "title": "ChargeToleranceSpec", + "description": "Charge tolerance parameters relevant to multiple simulation analysis types.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nabs_tol : PositiveFloat = 10000000000.0\n Absolute tolerance used as stop criteria when converging towards a solution.\nrel_tol : PositiveFloat = 1e-10\n Relative tolerance used as stop criteria when converging towards a solution.\nmax_iters : PositiveInt = 30\n Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.\nramp_up_iters : PositiveInt = 1\n In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.\n\nExample\n-------\n>>> import tidy3d as td\n>>> charge_settings = td.ChargeToleranceSpec(abs_tol=1e8, rel_tol=1e-10, max_iters=30)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "abs_tol": { + "title": "Absolute tolerance.", + "description": "Absolute tolerance used as stop criteria when converging towards a solution.", + "default": 10000000000.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "rel_tol": { + "title": "Relative tolerance.", + "description": "Relative tolerance used as stop criteria when converging towards a solution.", + "default": 1e-10, + "exclusiveMinimum": 0, + "type": "number" + }, + "max_iters": { + "title": "Maximum number of iterations.", + "description": "Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.", + "default": 30, + "exclusiveMinimum": 0, + "type": "integer" + }, + "ramp_up_iters": { + "title": "Ramp-up iterations.", + "description": "In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "ChargeToleranceSpec", + "enum": [ + "ChargeToleranceSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IsothermalSteadyChargeDCAnalysis": { + "title": "IsothermalSteadyChargeDCAnalysis", + "description": "Configures relevant steady-state DC simulation parameters for a charge simulation.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat = 300\n [units = K]. Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.\ntolerance_settings : ChargeToleranceSpec = ChargeToleranceSpec(attrs={}, abs_tol=10000000000.0, rel_tol=1e-10, max_iters=30, ramp_up_iters=1, type='ChargeToleranceSpec')\n convergence_dv : PositiveFloat = 1.0\n By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.\nfermi_dirac : bool = False\n Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "temperature": { + "title": "Temperature", + "description": "Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.", + "default": 300, + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "tolerance_settings": { + "title": "Tolerance settings", + "default": { + "attrs": {}, + "abs_tol": 10000000000.0, + "rel_tol": 1e-10, + "max_iters": 30, + "ramp_up_iters": 1, + "type": "ChargeToleranceSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ChargeToleranceSpec" + } + ] + }, + "convergence_dv": { + "title": "Bias step.", + "description": "By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.", + "default": 1.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "fermi_dirac": { + "title": "Fermi-Dirac statistics", + "description": "Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "default": false, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "IsothermalSteadyChargeDCAnalysis", + "enum": [ + "IsothermalSteadyChargeDCAnalysis" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UnsteadySpec": { + "title": "UnsteadySpec", + "description": "Defines an unsteady specification\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntime_step : PositiveFloat\n [units = sec]. Time step taken for each iteration of the time integration loop.\ntotal_time_steps : PositiveInt\n Specifies the total number of time steps run during the simulation.\n\nExample\n--------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "time_step": { + "title": "Time-step", + "description": "Time step taken for each iteration of the time integration loop.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "total_time_steps": { + "title": "Total time steps", + "description": "Specifies the total number of time steps run during the simulation.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "UnsteadySpec", + "enum": [ + "UnsteadySpec" + ], + "type": "string" + } + }, + "required": [ + "time_step", + "total_time_steps" + ], + "additionalProperties": false + }, + "UnsteadyHeatAnalysis": { + "title": "UnsteadyHeatAnalysis", + "description": "Configures relevant unsteady-state heat simulation parameters.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ninitial_temperature : PositiveFloat\n [units = K]. Initial value for the temperature field.\nunsteady_spec : UnsteadySpec\n Time step and total time steps for the unsteady simulation.\n\nExample\n-------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadyHeatAnalysis(\n... initial_temperature=300,\n... unsteady_spec=td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... ),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "initial_temperature": { + "title": "Initial temperature.", + "description": "Initial value for the temperature field.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "unsteady_spec": { + "title": "Unsteady specification", + "description": "Time step and total time steps for the unsteady simulation.", + "allOf": [ + { + "$ref": "#/definitions/UnsteadySpec" + } + ] + }, + "type": { + "title": "Type", + "default": "UnsteadyHeatAnalysis", + "enum": [ + "UnsteadyHeatAnalysis" + ], + "type": "string" + } + }, + "required": [ + "initial_temperature", + "unsteady_spec" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/HeatSimulation.json b/schemas/HeatSimulation.json new file mode 100644 index 0000000000..89d2d5d793 --- /dev/null +++ b/schemas/HeatSimulation.json @@ -0,0 +1,11281 @@ +{ + "title": "HeatSimulation", + "description": "Contains all information about heat simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, 1], Literal[0, 1], Literal[0, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).\nsources : Tuple[Annotated[Union[tidy3d.components.tcad.source.heat.HeatSource, tidy3d.components.tcad.source.coupled.HeatFromElectricSource, tidy3d.components.tcad.source.heat.UniformHeatSource], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of heat and/or charge sources.\nboundary_spec : Tuple[Annotated[Union[tidy3d.components.tcad.boundary.specification.HeatChargeBoundarySpec, tidy3d.components.tcad.boundary.specification.HeatBoundarySpec], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of boundary condition specifications.\nmonitors : Tuple[Annotated[Union[tidy3d.components.tcad.monitors.heat.TemperatureMonitor, tidy3d.components.tcad.monitors.charge.SteadyPotentialMonitor, tidy3d.components.tcad.monitors.charge.SteadyFreeCarrierMonitor, tidy3d.components.tcad.monitors.charge.SteadyEnergyBandMonitor, tidy3d.components.tcad.monitors.charge.SteadyElectricFieldMonitor, tidy3d.components.tcad.monitors.charge.SteadyCapacitanceMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Monitors in the simulation.\ngrid_spec : Union[UniformUnstructuredGrid, DistanceUnstructuredGrid]\n Grid specification for heat-charge simulation.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nanalysis_spec : Union[IsothermalSteadyChargeDCAnalysis, UnsteadyHeatAnalysis] = None\n The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.\n\nExample\n-------\n>>> import tidy3d as td\n>>> heat_sim = td.HeatSimulation( # doctest: +SKIP\n... size=(3.0, 3.0, 3.0),\n... structures=[\n... td.Structure(\n... geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=td.Medium(\n... permittivity=2.0, heat_spec=td.SolidSpec(\n... conductivity=1,\n... capacity=1,\n... )\n... ),\n... name=\"box\",\n... ),\n... ],\n... medium=td.Medium(permittivity=3.0, heat_spec=td.FluidSpec()),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.1),\n... sources=[td.HeatSource(rate=1, structures=[\"box\"])],\n... boundary_spec=[\n... td.HeatChargeBoundarySpec(\n... placement=td.StructureBoundary(structure=\"box\"),\n... condition=td.TemperatureBC(temperature=500),\n... )\n... ],\n... monitors=[td.TemperatureMonitor(size=(1, 2, 3), name=\"sample\")],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatSimulation", + "enum": [ + "HeatSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Heat and Charge sources", + "description": "List of heat and/or charge sources.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatSource": "#/definitions/HeatSource", + "HeatFromElectricSource": "#/definitions/HeatFromElectricSource", + "UniformHeatSource": "#/definitions/UniformHeatSource" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatSource" + }, + { + "$ref": "#/definitions/HeatFromElectricSource" + }, + { + "$ref": "#/definitions/UniformHeatSource" + } + ] + } + }, + "boundary_spec": { + "title": "Boundary Condition Specifications", + "description": "List of boundary condition specifications.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatChargeBoundarySpec": "#/definitions/HeatChargeBoundarySpec", + "HeatBoundarySpec": "#/definitions/HeatBoundarySpec" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatChargeBoundarySpec" + }, + { + "$ref": "#/definitions/HeatBoundarySpec" + } + ] + } + }, + "monitors": { + "title": "Monitors", + "description": "Monitors in the simulation.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureMonitor": "#/definitions/TemperatureMonitor", + "SteadyPotentialMonitor": "#/definitions/SteadyPotentialMonitor", + "SteadyFreeCarrierMonitor": "#/definitions/SteadyFreeCarrierMonitor", + "SteadyEnergyBandMonitor": "#/definitions/SteadyEnergyBandMonitor", + "SteadyElectricFieldMonitor": "#/definitions/SteadyElectricFieldMonitor", + "SteadyCapacitanceMonitor": "#/definitions/SteadyCapacitanceMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureMonitor" + }, + { + "$ref": "#/definitions/SteadyPotentialMonitor" + }, + { + "$ref": "#/definitions/SteadyFreeCarrierMonitor" + }, + { + "$ref": "#/definitions/SteadyEnergyBandMonitor" + }, + { + "$ref": "#/definitions/SteadyElectricFieldMonitor" + }, + { + "$ref": "#/definitions/SteadyCapacitanceMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Grid specification for heat-charge simulation.", + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformUnstructuredGrid": "#/definitions/UniformUnstructuredGrid", + "DistanceUnstructuredGrid": "#/definitions/DistanceUnstructuredGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformUnstructuredGrid" + }, + { + "$ref": "#/definitions/DistanceUnstructuredGrid" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "analysis_spec": { + "title": "Analysis specification.", + "description": "The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/IsothermalSteadyChargeDCAnalysis" + }, + { + "$ref": "#/definitions/UnsteadyHeatAnalysis" + } + ] + } + }, + "required": [ + "size", + "grid_spec" + ], + "additionalProperties": false, + "definitions": { + "NonlinearSusceptibility": { + "title": "NonlinearSusceptibility", + "description": "Model for an instantaneous nonlinear chi3 susceptibility.\nThe expression for the instantaneous nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nchi3 : float = 0\n [units = um^2 / V^2]. Chi3 nonlinear susceptibility.\nnumiters : Optional[PositiveInt] = None\n Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\chi_3` must be real.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "NonlinearSusceptibility", + "enum": [ + "NonlinearSusceptibility" + ], + "type": "string" + }, + "chi3": { + "title": "Chi3", + "description": "Chi3 nonlinear susceptibility.", + "default": 0, + "units": "um^2 / V^2", + "type": "number" + }, + "numiters": { + "title": "Number of iterations", + "description": "Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.", + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "additionalProperties": false + }, + "ComplexNumber": { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + "TwoPhotonAbsorption": { + "title": "TwoPhotonAbsorption", + "description": "Model for two-photon absorption (TPA) nonlinearity which gives an intensity-dependent\nabsorption of the form :math:`\\alpha = \\alpha_0 + \\beta I`.\nAlso includes free-carrier absorption (FCA) and free-carrier plasma dispersion (FCPD) effects.\nThe expression for the nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nbeta : Union[float, tidycomplex, ComplexNumber] = 0\n [units = um / W]. Coefficient for two-photon absorption (TPA).\ntau : NonNegativeFloat = 0\n [units = sec]. Lifetime for the free carriers created by two-photon absorption (TPA).\nsigma : NonNegativeFloat = 0\n [units = um^2]. Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.\ne_e : NonNegativeFloat = 1\n Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\ne_h : NonNegativeFloat = 1\n Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_e : float = 0\n [units = um^(3 e_e)]. Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_h : float = 0\n [units = um^(3 e_h)]. Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\nfreq0 : Optional[PositiveFloat] = None\n Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\beta` must be real.\n\n .. math::\n\n P_{NL} = P_{TPA} + P_{FCA} + P_{FCPD} \\\\\n P_{TPA} = -\\frac{4}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{2 i \\omega} |E|^2 E \\\\\n P_{FCA} = -\\frac{c_0 \\varepsilon_0 n_0 \\sigma N_f}{i \\omega} E \\\\\n \\frac{dN_f}{dt} = \\frac{8}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{8 q_e \\hbar \\omega} |E|^4 - \\frac{N_f}{\\tau} \\\\\n N_e = N_h = N_f \\\\\n P_{FCPD} = \\varepsilon_0 2 n_0 \\Delta n (N_f) E \\\\\n \\Delta n (N_f) = (c_e N_e^{e_e} + c_h N_h^{e_h})\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n The implementation is described in::\n\n N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si\n High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> tpa_model = TwoPhotonAbsorption(beta=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TwoPhotonAbsorption", + "enum": [ + "TwoPhotonAbsorption" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "beta": { + "title": "TPA coefficient", + "description": "Coefficient for two-photon absorption (TPA).", + "default": 0, + "units": "um / W", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "tau": { + "title": "Carrier lifetime", + "description": "Lifetime for the free carriers created by two-photon absorption (TPA).", + "default": 0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "sigma": { + "title": "FCA cross section", + "description": "Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.", + "default": 0, + "units": "um^2", + "minimum": 0, + "type": "number" + }, + "e_e": { + "title": "Electron exponent", + "description": "Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "e_h": { + "title": "Hole exponent", + "description": "Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "c_e": { + "title": "Electron coefficient", + "description": "Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_e)", + "type": "number" + }, + "c_h": { + "title": "Hole coefficient", + "description": "Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_h)", + "type": "number" + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "freq0": { + "title": "Central frequency", + "description": "Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "KerrNonlinearity": { + "title": "KerrNonlinearity", + "description": "Model for Kerr nonlinearity which gives an intensity-dependent refractive index\nof the form :math:`n = n_0 + n_2 I`. The expression for the nonlinear polarization\nis given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nn2 : Union[tidycomplex, ComplexNumber] = 0\n [units = um^2 / W]. Nonlinear refractive index in the Kerr nonlinearity.\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\n_2` must be real.\n\n This model is equivalent to a :class:`.NonlinearSusceptibility`; the\n relation between the parameters is given below.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E \\\\\n n_2 = \\frac{3}{4 n_0^2 \\varepsilon_0 c_0} \\chi_3\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n To simulate nonlinear loss, consider instead using a :class:`.TwoPhotonAbsorption`\n model, which implements a more physical dispersive loss of the form\n :math:`\\chi_{TPA} = i \\frac{c_0 n_0 \\beta}{\\omega} I`.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> kerr_model = KerrNonlinearity(n2=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "KerrNonlinearity", + "enum": [ + "KerrNonlinearity" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "n2": { + "title": "Nonlinear refractive index", + "description": "Nonlinear refractive index in the Kerr nonlinearity.", + "default": 0, + "units": "um^2 / W", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "additionalProperties": false + }, + "NonlinearSpec": { + "title": "NonlinearSpec", + "description": "Abstract specification for adding nonlinearities to a medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmodels : Tuple[Union[NonlinearSusceptibility, TwoPhotonAbsorption, KerrNonlinearity], ...] = ()\n The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.\nnum_iters : PositiveInt = 5\n Number of iterations for solving nonlinear constitutive relation.\n\nNote\n----\nThe nonlinear constitutive relation is solved iteratively; it may not converge\nfor strong nonlinearities. Increasing ``num_iters`` can help with convergence.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)\n>>> nonlinear_spec = NonlinearSpec(models=[nonlinear_susceptibility])\n>>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "models": { + "title": "Nonlinear models", + "description": "The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSusceptibility" + }, + { + "$ref": "#/definitions/TwoPhotonAbsorption" + }, + { + "$ref": "#/definitions/KerrNonlinearity" + } + ] + } + }, + "num_iters": { + "title": "Number of iterations", + "description": "Number of iterations for solving nonlinear constitutive relation.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "NonlinearSpec", + "enum": [ + "NonlinearSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SpaceModulation": { + "title": "SpaceModulation", + "description": "The modulation profile with a user-supplied spatial distribution of\namplitude and phase.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : Union[float, SpatialDataArray] = 1\n Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.\nphase : Union[float, SpatialDataArray] = 0\n [units = rad]. Phase of modulation that can vary spatially.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Method of interpolation to use to obtain values at spatial locations on the Yee grids.\n\nNote\n----\n.. math::\n\n amp\\_space(r) = amplitude(r) \\cdot e^{i \\cdot phase(r)}\n\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> amp = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> phase = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> space = SpaceModulation(amplitude=amp, phase=phase)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SpaceModulation", + "enum": [ + "SpaceModulation" + ], + "type": "string" + }, + "amplitude": { + "title": "Amplitude of modulation in space", + "description": "Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.", + "default": 1, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "phase": { + "title": "Phase of modulation in space", + "description": "Phase of modulation that can vary spatially.", + "default": 0, + "units": "rad", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Method of interpolation to use to obtain values at spatial locations on the Yee grids.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContinuousWaveTimeModulation": { + "title": "ContinuousWaveTimeModulation", + "description": "Class describing modulation with a harmonic time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Modulation frequency.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t}\n\nNote\n----\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\n\nExample\n-------\n>>> cw = ContinuousWaveTimeModulation(freq0=200e12, amplitude=1, phase=0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWaveTimeModulation", + "enum": [ + "ContinuousWaveTimeModulation" + ], + "type": "string" + }, + "freq0": { + "title": "Modulation Frequency", + "description": "Modulation frequency.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "freq0" + ], + "additionalProperties": false + }, + "SpaceTimeModulation": { + "title": "SpaceTimeModulation", + "description": "Space-time modulation applied to a medium, adding\non top of the time-independent part.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nspace_modulation : SpaceModulation = SpaceModulation(attrs={}, type='SpaceModulation', amplitude=1.0, phase=0.0, interp_method='nearest')\n Space modulation part from the separable SpaceTimeModulation.\ntime_modulation : ContinuousWaveTimeModulation\n Time modulation part from the separable SpaceTimeModulation.\n\n\nNote\n----\nThe space-time modulation must be separable in space and time.\ne.g. when applied to permittivity,\n\n.. math::\n\n \\delta \\epsilon(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "space_modulation": { + "title": "Space modulation", + "description": "Space modulation part from the separable SpaceTimeModulation.", + "default": { + "attrs": {}, + "type": "SpaceModulation", + "amplitude": 1.0, + "phase": 0.0, + "interp_method": "nearest" + }, + "allOf": [ + { + "$ref": "#/definitions/SpaceModulation" + } + ] + }, + "time_modulation": { + "title": "Time modulation", + "description": "Time modulation part from the separable SpaceTimeModulation.", + "allOf": [ + { + "$ref": "#/definitions/ContinuousWaveTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "SpaceTimeModulation", + "enum": [ + "SpaceTimeModulation" + ], + "type": "string" + } + }, + "required": [ + "time_modulation" + ], + "additionalProperties": false + }, + "ModulationSpec": { + "title": "ModulationSpec", + "description": "Specification adding space-time modulation to the non-dispersive part of medium\nincluding relative permittivity at infinite frequency and electric conductivity.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npermittivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.\nconductivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of electric conductivity applied on top of the base conductivity.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "permittivity": { + "title": "Space-time modulation of relative permittivity", + "description": "Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "conductivity": { + "title": "Space-time modulation of conductivity", + "description": "Space-time modulation of electric conductivity applied on top of the base conductivity.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "ModulationSpec", + "enum": [ + "ModulationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VisualizationSpec": { + "title": "VisualizationSpec", + "description": "Defines specification for visualization when used with plotting functions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfacecolor : str = \n Color applied to the faces in visualization.\nedgecolor : Optional[str] = \n Color applied to the edges in visualization.\nalpha : Optional[ConstrainedFloatValue] = 1.0\n Opacity/alpha value in plotting between 0 and 1.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "facecolor": { + "title": "Face color", + "description": "Color applied to the faces in visualization.", + "default": "", + "type": "string" + }, + "edgecolor": { + "title": "Edge color", + "description": "Color applied to the edges in visualization.", + "default": "", + "type": "string" + }, + "alpha": { + "title": "Opacity", + "description": "Opacity/alpha value in plotting between 0 and 1.", + "default": 1.0, + "minimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "VisualizationSpec", + "enum": [ + "VisualizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FluidSpec": { + "title": "FluidSpec", + "description": "Fluid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidSpec", + "enum": [ + "FluidSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SolidSpec": { + "title": "SolidSpec", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidSpec", + "enum": [ + "SolidSpec" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "SolidMedium": { + "title": "SolidMedium", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidMedium", + "enum": [ + "SolidMedium" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "FluidMedium": { + "title": "FluidMedium", + "description": "Fluid medium. Heat simulations will not solve for temperature\nin a structure that has a medium with this 'heat_spec'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\n\nExample\n-------\n>>> solid = FluidMedium()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidMedium", + "enum": [ + "FluidMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Medium": { + "title": "Medium", + "description": "Dispersionless medium. Mediums define the optical properties of the materials within the simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n In a dispersion-less medium, the displacement field :math:`D(t)` reacts instantaneously to the applied\n electric field :math:`E(t)`.\n\n .. math::\n\n D(t) = \\epsilon E(t)\n\nExample\n-------\n>>> dielectric = Medium(permittivity=4.0, name='my_medium')\n>>> eps = dielectric.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Introduction on Tidy3D working principles <../../notebooks/Primer.html#Mediums>`_\n * `Index <../../notebooks/docs/features/medium.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_\n\n**GUI**\n * `Mediums `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium", + "enum": [ + "Medium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "additionalProperties": false + }, + "HammerstadSurfaceRoughness": { + "title": "HammerstadSurfaceRoughness", + "description": "Modified Hammerstad surface roughness model. It's a popular model that works well\nunder 5 GHz for surface roughness below 2 micrometer RMS.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrq : PositiveFloat\n [units = um]. RMS peak-to-valley height (Rq) of the surface roughness.\nroughness_factor : ConstrainedFloatValue = 2.0\n Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n 1 + (RF-1) \\frac{2}{\\pi}\\arctan(1.4\\frac{R_q^2}{\\delta^2})\n\n where :math:`\\delta` is skin depth, :math:`R_q` the RMS peak-to-vally height, and RF\n roughness factor.\n\nNote\n----\nThis model is based on:\n\n Y. Shlepnev, C. Nwachukwu, \"Roughness characterization for interconnect analysis\",\n 2011 IEEE International Symposium on Electromagnetic Compatibility,\n (DOI: 10.1109/ISEMC.2011.6038367), 2011.\n\n V. Dmitriev-Zdorov, B. Simonovich, I. Kochikov, \"A Causal Conductor Roughness Model\n and its Effect on Transmission Line Characteristics\", Signal Integrity Journal, 2018.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HammerstadSurfaceRoughness", + "enum": [ + "HammerstadSurfaceRoughness" + ], + "type": "string" + }, + "rq": { + "title": "RMS Peak-to-Valley Height", + "description": "RMS peak-to-valley height (Rq) of the surface roughness.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "roughness_factor": { + "title": "Roughness Factor", + "description": "Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.", + "default": 2.0, + "exclusiveMinimum": 1.0, + "type": "number" + } + }, + "required": [ + "rq" + ], + "additionalProperties": false + }, + "HuraySurfaceRoughness": { + "title": "HuraySurfaceRoughness", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HuraySurfaceRoughness", + "enum": [ + "HuraySurfaceRoughness" + ], + "type": "string" + }, + "relative_area": { + "title": "Relative Area", + "description": "Relative area of the matte base compared to a flat surface", + "default": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients for surface ratio and sphere radius", + "description": "List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.", + "units": [ + null, + "um" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "SurfaceImpedanceFitterParam": { + "title": "SurfaceImpedanceFitterParam", + "description": "Advanced parameters for fitting surface impedance of a :class:`.LossyMetalMedium`.\nInternally, the quantity to be fitted is surface impedance divided by ``-1j * \\omega``.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_num_poles : PositiveInt = 5\n Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.\ntolerance_rms : NonNegativeFloat = 0.001\n Tolerance in fitting.\nfrequency_sampling_points : PositiveInt = 20\n Number of sampling frequencies used in fitting.\nlog_sampling : bool = True\n Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "max_num_poles": { + "title": "Maximal Number Of Poles", + "description": "Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "tolerance_rms": { + "title": "Tolerance In Fitting", + "description": "Tolerance in fitting.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "frequency_sampling_points": { + "title": "Number Of Sampling Frequencies", + "description": "Number of sampling frequencies used in fitting.", + "default": 20, + "exclusiveMinimum": 0, + "type": "integer" + }, + "log_sampling": { + "title": "Frequencies Sampling In Log Scale", + "description": "Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedanceFitterParam", + "enum": [ + "SurfaceImpedanceFitterParam" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LossyMetalMedium": { + "title": "LossyMetalMedium", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Frequency range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "LossyMetalMedium", + "enum": [ + "LossyMetalMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "enum": [ + 1 + ], + "type": "integer" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "roughness": { + "title": "Surface Roughness Model", + "description": "Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.", + "discriminator": { + "propertyName": "type", + "mapping": { + "HammerstadSurfaceRoughness": "#/definitions/HammerstadSurfaceRoughness", + "HuraySurfaceRoughness": "#/definitions/HuraySurfaceRoughness" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HammerstadSurfaceRoughness" + }, + { + "$ref": "#/definitions/HuraySurfaceRoughness" + } + ] + }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "fit_param": { + "title": "Fitting Parameters For Surface Impedance", + "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", + "default": { + "attrs": {}, + "max_num_poles": 5, + "tolerance_rms": 0.001, + "frequency_sampling_points": 20, + "log_sampling": true, + "type": "SurfaceImpedanceFitterParam" + }, + "allOf": [ + { + "$ref": "#/definitions/SurfaceImpedanceFitterParam" + } + ] + } + }, + "required": [ + "frequency_range" + ], + "additionalProperties": false + }, + "PoleResidue": { + "title": "PoleResidue", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PoleResidue", + "enum": [ + "PoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + } + }, + "additionalProperties": false + }, + "Sellmeier": { + "title": "Sellmeier", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Sellmeier", + "enum": [ + "Sellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Lorentz": { + "title": "Lorentz", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Lorentz", + "enum": [ + "Lorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number", + "minimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Debye": { + "title": "Debye", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Debye", + "enum": [ + "Debye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Drude": { + "title": "Drude", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Drude", + "enum": [ + "Drude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "PECMedium": { + "title": "PECMedium", + "description": "Perfect electrical conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PECs, must import ``tidy3d.PEC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PECMedium", + "enum": [ + "PECMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AnisotropicMedium": { + "title": "AnisotropicMedium", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMedium", + "enum": [ + "AnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "FullyAnisotropicMedium": { + "title": "FullyAnisotropicMedium", + "description": "Fully anisotropic medium including all 9 components of the permittivity and conductivity\ntensors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]\n [units = None (relative permittivity)]. Relative permittivity tensor.\nconductivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n [units = S/um]. Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n Provided permittivity tensor and the symmetric part of the conductivity tensor must\n have coinciding main directions. A non-symmetric conductivity tensor can be used to model\n magneto-optic effects. Note that dispersive properties and subpixel averaging are currently not\n supported for fully anisotropic materials.\n\nNote\n----\n\n Simulations involving fully anisotropic materials are computationally more intensive, thus,\n they take longer time to complete. This increase strongly depends on the filling fraction of\n the simulation domain by fully anisotropic materials, varying approximately in the range from\n 1.5 to 5. The cost of running a simulation is adjusted correspondingly.\n\nExample\n-------\n>>> perm = [[2, 0, 0], [0, 1, 0], [0, 0, 3]]\n>>> cond = [[0.1, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> anisotropic_dielectric = FullyAnisotropicMedium(permittivity=perm, conductivity=cond)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "FullyAnisotropicMedium", + "enum": [ + "FullyAnisotropicMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity tensor.", + "default": [ + [ + 1, + 0, + 0 + ], + [ + 0, + 1, + 0 + ], + [ + 0, + 0, + 1 + ] + ], + "units": "None (relative permittivity)", + "type": "ArrayLike" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "units": "S/um", + "type": "ArrayLike" + } + }, + "additionalProperties": false + }, + "PermittivityDataset": { + "title": "PermittivityDataset", + "description": "Dataset storing the diagonal components of the permittivity tensor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\neps_xx : ScalarFieldDataArray\n Spatial distribution of the xx-component of the relative permittivity.\neps_yy : ScalarFieldDataArray\n Spatial distribution of the yy-component of the relative permittivity.\neps_zz : ScalarFieldDataArray\n Spatial distribution of the zz-component of the relative permittivity.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> sclr_fld = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = PermittivityDataset(eps_xx=sclr_fld, eps_yy=sclr_fld, eps_zz=sclr_fld)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityDataset", + "enum": [ + "PermittivityDataset" + ], + "type": "string" + }, + "eps_xx": { + "title": "DataArray", + "description": "Spatial distribution of the xx-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_yy": { + "title": "DataArray", + "description": "Spatial distribution of the yy-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_zz": { + "title": "DataArray", + "description": "Spatial distribution of the zz-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "eps_xx", + "eps_yy", + "eps_zz" + ], + "additionalProperties": false + }, + "TriangularGridDataset": { + "title": "TriangularGridDataset", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangularGridDataset", + "enum": [ + "TriangularGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "normal_axis": { + "title": "Grid Axis", + "description": "Orientation of the grid.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "normal_pos": { + "title": "Position", + "description": "Coordinate of the grid along the normal direction.", + "type": "number" + } + }, + "required": [ + "points", + "values", + "cells", + "normal_axis", + "normal_pos" + ], + "additionalProperties": false + }, + "TetrahedralGridDataset": { + "title": "TetrahedralGridDataset", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TetrahedralGridDataset", + "enum": [ + "TetrahedralGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "points", + "values", + "cells" + ], + "additionalProperties": false + }, + "CustomMedium": { + "title": "CustomMedium", + "description": ":class:`.Medium` with user-supplied permittivity distribution.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\neps_dataset : Optional[PermittivityDataset] = None\n [To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.\npermittivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = None (relative permittivity)]. Spatial profile of relative permittivity.\nconductivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = S/um]. Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> dielectric = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> eps = dielectric.eps_model(200e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomMedium", + "enum": [ + "CustomMedium" + ], + "type": "string" + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + }, + "eps_dataset": { + "title": "Permittivity Dataset", + "description": "[To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.", + "allOf": [ + { + "$ref": "#/definitions/PermittivityDataset" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Spatial profile of relative permittivity.", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "units": "S/um", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + }, + "additionalProperties": false + }, + "CustomPoleResidue": { + "title": "CustomPoleResidue", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomPoleResidue", + "enum": [ + "CustomPoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf" + ], + "additionalProperties": false + }, + "CustomSellmeier": { + "title": "CustomSellmeier", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomSellmeier", + "enum": [ + "CustomSellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "CustomLorentz": { + "title": "CustomLorentz", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomLorentz", + "enum": [ + "CustomLorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDebye": { + "title": "CustomDebye", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDebye", + "enum": [ + "CustomDebye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDrude": { + "title": "CustomDrude", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDrude", + "enum": [ + "CustomDrude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomAnisotropicMedium": { + "title": "CustomAnisotropicMedium", + "description": "Diagonally anisotropic medium with spatially varying permittivity in each component.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\ninterp_method : Optional[Literal['nearest', 'linear']] = None\n When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.\nsubpixel : Optional[bool] = None\n This field is ignored. Please set ``subpixel`` in each component\n\nNote\n----\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> x = np.linspace(-1, 1, Nx)\n>>> y = np.linspace(-1, 1, Ny)\n>>> z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=x, y=y, z=z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> medium_xx = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> medium_yy = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> d_epsilon = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> medium_zz = CustomLorentz(eps_inf=permittivity, coeffs=[(d_epsilon,f,delta),])\n>>> anisotropic_dielectric = CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomAnisotropicMedium", + "enum": [ + "CustomAnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This field is ignored. Please set ``subpixel`` in each component", + "type": "boolean" + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "LinearHeatPerturbation": { + "title": "LinearHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a linear function of\ntemperature.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n [units = K]. Temperature range in which perturbation model is valid.\ntemperature_ref : NonNegativeFloat\n [units = K]. Temperature at which perturbation is zero.\ncoeff : Union[float, tidycomplex, ComplexNumber]\n [units = 1/K]. Sensitivity (derivative) of perturbation with respect to temperature.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{coeff} \\times (T - \\text{temperature\\_ref}),\n\n where ``coeff`` is the parameter's sensitivity (thermo-optic coefficient) to temperature and\n ``temperature_ref`` is the reference temperature point. A temperature range in which such\n a model is deemed accurate may be provided as a field ``temperature_range``\n (default: ``[0, inf]``). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.0001,\n... temperature_range=[200, 500],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearHeatPerturbation", + "enum": [ + "LinearHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "temperature_ref": { + "title": "Reference temperature", + "description": "Temperature at which perturbation is zero.", + "units": "K", + "minimum": 0, + "type": "number" + }, + "coeff": { + "title": "Thermo-optic Coefficient", + "description": "Sensitivity (derivative) of perturbation with respect to temperature.", + "units": "1/K", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "required": [ + "temperature_ref", + "coeff" + ], + "additionalProperties": false + }, + "CustomHeatPerturbation": { + "title": "CustomHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a custom function of\ntemperature defined as an array of perturbation values at sample temperature points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n [units = K]. Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.\nperturbation_values : HeatDataArray\n Sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\n Notes\n -----\n\n The linear\n interpolation is used to calculate perturbation values between sample temperature points. For\n temperature values outside of the provided sample region the perturbation value is extrapolated\n as a constant.\n The temperature range, ``temperature_range``, in which the perturbation model is assumed to be\n accurate is calculated automatically as the minimal and maximal sample temperature points.\n Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> from tidy3d import HeatDataArray\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomHeatPerturbation", + "enum": [ + "CustomHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.", + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "Sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "LinearChargePerturbation": { + "title": "LinearChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a linear function of\nelectron and hole densities:\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of electrons densities in which perturbation model is valid.\nhole_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of holes densities in which perturbation model is valid.\nelectron_ref : NonNegativeFloat\n [units = 1/cm^3]. Electron density value at which there is no perturbation due to electrons's presence.\nhole_ref : NonNegativeFloat\n [units = 1/cm^3]. Hole density value at which there is no perturbation due to holes' presence.\nelectron_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to electron density.\nhole_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to hole density.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{electron\\_coeff} \\times (N_e - \\text{electron\\_ref})\n + \\text{hole\\_coeff} \\times (N_h - \\text{hole\\_ref}),\n\n where ``electron_coeff`` and ``hole_coeff`` are the parameter's sensitivities to electron and\n hole densities, while ``electron_ref`` and ``hole_ref`` are reference electron and hole density\n values. Ranges of electron and hole densities in which such\n a model is deemed accurate may be provided as fields ``electron_range`` and ``hole_range``\n (default: ``[0, inf]`` each). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``electron_range`` x ``hole_range`` due to\n perturbations and raise a warning if this check fails. A warning is also issued if\n the perturbation model is evaluated outside of ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearChargePerturbation", + "enum": [ + "LinearChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "electron_ref": { + "title": "Reference Electron Density", + "description": "Electron density value at which there is no perturbation due to electrons's presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "hole_ref": { + "title": "Reference Hole Density", + "description": "Hole density value at which there is no perturbation due to holes' presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "electron_coeff": { + "title": "Sensitivity to Electron Density", + "description": "Sensitivity (derivative) of perturbation with respect to electron density.", + "units": "cm^3", + "type": "number" + }, + "hole_coeff": { + "title": "Sensitivity to Hole Density", + "description": "Sensitivity (derivative) of perturbation with respect to hole density.", + "units": "cm^3", + "type": "number" + } + }, + "required": [ + "electron_ref", + "hole_ref", + "electron_coeff", + "hole_coeff" + ], + "additionalProperties": false + }, + "CustomChargePerturbation": { + "title": "CustomChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a custom function of\nelectron and hole densities defined as a two-dimensional array of perturbation values at sample\nelectron and hole density points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nhole_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nperturbation_values : ChargeDataArray\n 2D array (vs electron and hole densities) of sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\nNotes\n-----\n\n The linear interpolation is used to calculate perturbation\n values between sample points. For electron and hole density values outside of the provided\n sample region the perturbation value is extrapolated as a constant.\n The electron and hole density ranges, ``electron_range`` and ``hole_range``, in which\n the perturbation model is assumed to be accurate is calculated automatically as the minimal and\n maximal density values provided in ``perturbation_values``. Wherever is applied, Tidy3D will\n check that the parameter's value does not go out of its physical bounds within\n ``electron_range`` x ``hole_range`` due to perturbations and raise a warning if this check\n fails. A warning is also issued if the perturbation model is evaluated outside of\n ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> from tidy3d import ChargeDataArray\n>>> perturbation_data = ChargeDataArray(\n... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],\n... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),\n... )\n>>> charge_perturb = CustomChargePerturbation(\n... perturbation_values=perturbation_data,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomChargePerturbation", + "enum": [ + "CustomChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "2D array (vs electron and hole densities) of sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "ParameterPerturbation": { + "title": "ParameterPerturbation", + "description": "Stores information about parameter perturbations due to different physical effect. If both\nheat and charge perturbation models are included their effects are superimposed.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nheat : Union[LinearHeatPerturbation, CustomHeatPerturbation] = None\n Heat perturbation to apply.\ncharge : Union[LinearChargePerturbation, CustomChargePerturbation] = None\n Charge perturbation to apply.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, CustomHeatPerturbation, HeatDataArray\n>>>\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )\n>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "heat": { + "title": "Heat Perturbation", + "description": "Heat perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearHeatPerturbation": "#/definitions/LinearHeatPerturbation", + "CustomHeatPerturbation": "#/definitions/CustomHeatPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearHeatPerturbation" + }, + { + "$ref": "#/definitions/CustomHeatPerturbation" + } + ] + }, + "charge": { + "title": "Charge Perturbation", + "description": "Charge perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearChargePerturbation": "#/definitions/LinearChargePerturbation", + "CustomChargePerturbation": "#/definitions/CustomChargePerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearChargePerturbation" + }, + { + "$ref": "#/definitions/CustomChargePerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "ParameterPerturbation", + "enum": [ + "ParameterPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityPerturbation": { + "title": "PermittivityPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\npermittivity and conductivity.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_eps : Optional[ParameterPerturbation] = None\n Perturbation model for permittivity.\ndelta_sigma : Optional[ParameterPerturbation] = None\n Perturbation model for conductivity.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, PermittivityPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> delta_eps = ParameterPerturbation(heat=heat_perturb)\n>>> delta_sigma = ParameterPerturbation(charge=charge_perturb)\n>>> permittivity_pb = PermittivityPerturbation(delta_eps=delta_eps, delta_sigma=delta_sigma)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_eps": { + "title": "Permittivity Perturbation", + "description": "Perturbation model for permittivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_sigma": { + "title": "Conductivity Perturbation", + "description": "Perturbation model for conductivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PermittivityPerturbation", + "enum": [ + "PermittivityPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IndexPerturbation": { + "title": "IndexPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\nrefractive index, n and k.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_n : Optional[ParameterPerturbation] = None\n Perturbation of the real part of refractive index.\ndelta_k : Optional[ParameterPerturbation] = None\n Perturbation of the imaginary part of refractive index.\nfreq : NonNegativeFloat\n [units = Hz]. Frequency to evaluate permittivity at (Hz).\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, IndexPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> dn_pb = ParameterPerturbation(heat=heat_perturb)\n>>> dk_pb = ParameterPerturbation(charge=charge_perturb)\n>>> index_pb = IndexPerturbation(delta_n=dn_pb, delta_k=dk_pb, freq=C_0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_n": { + "title": "Refractive Index Perturbation", + "description": "Perturbation of the real part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_k": { + "title": "Exctinction Coefficient Perturbation", + "description": "Perturbation of the imaginary part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "freq": { + "title": "Frequency", + "description": "Frequency to evaluate permittivity at (Hz).", + "units": "Hz", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "IndexPerturbation", + "enum": [ + "IndexPerturbation" + ], + "type": "string" + } + }, + "required": [ + "freq" + ], + "additionalProperties": false + }, + "PerturbationMedium": { + "title": "PerturbationMedium", + "description": "Dispersionless medium with perturbations. Perturbation model can be defined either directly\nthrough providing ``permittivity_perturbation`` and ``conductivity_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\npermittivity_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. List of heat and/or charge perturbations to permittivity.\nconductivity_perturbation : Optional[ParameterPerturbation] = None\n [units = S/um]. List of heat and/or charge perturbations to permittivity.\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> dielectric = PerturbationMedium(\n... permittivity=4.0,\n... permittivity_perturbation=ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... ),\n... name='my_medium',\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationMedium", + "enum": [ + "PerturbationMedium" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "permittivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "conductivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "S/um", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + }, + "additionalProperties": false + }, + "PerturbationPoleResidue": { + "title": "PerturbationPoleResidue", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationPoleResidue", + "enum": [ + "PerturbationPoleResidue" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + }, + "eps_inf_perturbation": { + "title": "Perturbation of Epsilon at Infinity", + "description": "Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "poles_perturbation": { + "title": "Perturbations of Poles", + "description": "Perturbations to poles of the model.", + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "$ref": "#/definitions/ParameterPerturbation" + }, + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + } + }, + "additionalProperties": false + }, + "Medium2D": { + "title": "Medium2D", + "description": "2D diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nss : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.\ntt : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> medium2d = Medium2D(ss=drude_medium, tt=drude_medium)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium2D", + "enum": [ + "Medium2D" + ], + "type": "string" + }, + "ss": { + "title": "SS Component", + "description": "Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + }, + "tt": { + "title": "TT Component", + "description": "Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + } + }, + "required": [ + "ss", + "tt" + ], + "additionalProperties": false + }, + "AnisotropicMediumFromMedium2D": { + "title": "AnisotropicMediumFromMedium2D", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMediumFromMedium2D", + "enum": [ + "AnisotropicMediumFromMedium2D" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "ChargeConductorMedium": { + "title": "ChargeConductorMedium", + "description": "Conductor medium for conduction simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : PositiveFloat\n [units = S/um]. Electric conductivity of material in units of S/um.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeConductorMedium(conductivity=3)\n\nNote\n----\n A relative permittivity will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeConductorMedium", + "enum": [ + "ChargeConductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "conductivity": { + "title": "Electric conductivity", + "description": "Electric conductivity of material in units of S/um.", + "units": "S/um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "ChargeInsulatorMedium": { + "title": "ChargeInsulatorMedium", + "description": "Insulating medium. Conduction simulations will not solve for electric\npotential in a structure that has a medium with this 'charge'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeInsulatorMedium()\n>>> solid2 = td.ChargeInsulatorMedium(permittivity=1.1)\n\nNote\n----\n A relative permittivity :math:`\\varepsilon` will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeInsulatorMedium", + "enum": [ + "ChargeInsulatorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + } + }, + "additionalProperties": false + }, + "CaugheyThomasMobility": { + "title": "CaugheyThomasMobility", + "description": "The Caughey-Thomas temperature-dependent carrier mobility model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu_min : PositiveFloat\n Minimum electron mobility at reference temperature (300K) in cm^2/V-s. \nmu : PositiveFloat\n Reference mobility at reference temperature (300K) in cm^2/V-s\nexp_2 : float\n exp_N : PositiveFloat\n Exponent for doping dependence of mobility at reference temperature (300K).\nref_N : PositiveFloat\n Reference doping at reference temperature (300K) in #/cm^3.\nexp_1 : float\n Exponent of thermal dependence of minimum mobility.\nexp_3 : float\n Exponent of thermal dependence of reference doping.\nexp_4 : float\n Exponent of thermal dependence of the doping exponent effect.\n\nNotes\n-----\n The general form of the Caughey-Thomas mobility model [1]_ is of the form:\n\n .. math::\n\n \\mu_0 = \\frac{\\mu_{max} - \\mu_{min}}{1 + \\left(N/N_{ref}\\right)^z} + \\mu_{min}\n\nwhere :math:`\\mu_0` represents the low-field mobility and :math:`N` is the total doping (acceptors + donors).\n:math:`\\mu_{max}`, :math:`\\mu_{min}`, :math:`z`, and :math:`N_{ref}` are temperature dependent,\nthe dependence being of the form\n\n.. math::\n\n \\phi = \\phi_{ref} \\left( \\frac{T}{T_{ref}}\\right)^\\alpha\n\nand :math:`T_{ref}` is taken to be 300K.\n\nThe complete form (with temperature effects) for the low-field mobility can be written as\n\n.. math::\n\n \\mu_0 = \\frac{\\mu_{max}(\\frac{T}{T_{ref}})^{\\alpha_2} - \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}}{1 + \\left(N/N_{ref}(\\frac{T}{T_{ref}})^{\\alpha_3}\\right)^{\\alpha_N(\\frac{T}{T_{ref}})^{\\alpha_4}}} + \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}\n\nThe following table maps the symbols used in the equations above with the names used in the code:\n\n.. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`\\mu_{min}`\n - ``mu_min``\n - Minimum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\mu_{max}`\n - ``mu_n``\n - Maximum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\alpha_1`\n - ``exp_1``\n - Exponent for temperature dependence of the minimum mobility coefficient\n * - :math:`\\alpha_2`\n - ``exp_2``\n - Exponent for temperature dependence of the maximum mobility coefficient\n * - :math:`\\alpha_N`\n - ``exp_N``\n - Exponent for doping dependence.\n * - :math:`\\alpha_4`\n - ``exp_4``\n - Exponent for the temperature dependence of the exponent :math:`\\alpha_N`\n * - :math:`N_{ref}`\n - ``ref_N``,\n - Reference doping parameter\n\n\n.. [1] M. Caughey and R.E. Thomas. Carrier mobilities in silicon empirically related to doping\n and field. Proceedings of the IEEE, 55(12):2192\u20132193, December 1967\n\nExample\n-------\n >>> import tidy3d as td\n >>> mobility_Si_n = td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n >>> mobility_Si_p = td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n\n\nWarning\n-------\nThere are some current limitations of this model:\n\n- High electric field effects not yet supported.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu_min": { + "title": "$\\mu_{min}$ Minimum electron mobility", + "description": "Minimum electron mobility at reference temperature (300K) in cm^2/V-s. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "mu": { + "title": "Reference mobility", + "description": "Reference mobility at reference temperature (300K) in cm^2/V-s", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_2": { + "title": "Exponent for temperature dependent behavior of reference mobility", + "type": "number" + }, + "exp_N": { + "title": "Exponent for doping dependence of mobility.", + "description": "Exponent for doping dependence of mobility at reference temperature (300K).", + "exclusiveMinimum": 0, + "type": "number" + }, + "ref_N": { + "title": "Reference doping", + "description": "Reference doping at reference temperature (300K) in #/cm^3.", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_1": { + "title": "Exponent of thermal dependence of minimum mobility.", + "description": "Exponent of thermal dependence of minimum mobility.", + "type": "number" + }, + "exp_3": { + "title": "Exponent of thermal dependence of reference doping.", + "description": "Exponent of thermal dependence of reference doping.", + "type": "number" + }, + "exp_4": { + "title": "Exponent of thermal dependence of the doping exponent effect.", + "description": "Exponent of thermal dependence of the doping exponent effect.", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CaugheyThomasMobility", + "enum": [ + "CaugheyThomasMobility" + ], + "type": "string" + } + }, + "required": [ + "mu_min", + "mu", + "exp_2", + "exp_N", + "ref_N", + "exp_1", + "exp_3", + "exp_4" + ], + "additionalProperties": false + }, + "ConstantMobilityModel": { + "title": "ConstantMobilityModel", + "description": "Constant mobility model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu : NonNegativeFloat\n [units = cm\u00b2/V-s]. Mobility\n\nExample\n-------\n>>> import tidy3d as td\n>>> mobility_model = td.ConstantMobilityModel(mu=1500)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu": { + "title": "Mobility", + "description": "Mobility", + "units": "cm\u00b2/V-s", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ConstantMobilityModel", + "enum": [ + "ConstantMobilityModel" + ], + "type": "string" + } + }, + "required": [ + "mu" + ], + "additionalProperties": false + }, + "AugerRecombination": { + "title": "AugerRecombination", + "description": "Parameters for the Auger recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nc_n : PositiveFloat\n Constant for electrons in cm^6/s\nc_p : PositiveFloat\n Constant for holes in cm^6/s\n\nNotes\n-----\n\n The Auger recombination rate ``R_A`` is primarily defined by the electrons and holes Auger recombination\n coefficients, :math:`C_n` and :math:`C_p`, respectively.\n\n .. math::\n\n R_A = \\left( C_n n + C_p p \\right) \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32,\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "c_n": { + "title": "Constant for electrons", + "description": "Constant for electrons in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "c_p": { + "title": "Constant for holes", + "description": "Constant for holes in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AugerRecombination", + "enum": [ + "AugerRecombination" + ], + "type": "string" + } + }, + "required": [ + "c_n", + "c_p" + ], + "additionalProperties": false + }, + "RadiativeRecombination": { + "title": "RadiativeRecombination", + "description": "Defines the parameters for the radiative recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr_const : float\n Radiation constant in cm^3/s\n\nNotes\n-----\n\n This is a direct recombination model primarily defined by a radiative recombination coefficient :math:`R_{\\text{rad}}`.\n\n .. math::\n\n R_{\\text{rad}} = C \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r_const": { + "title": "Radiation constant in cm^3/s", + "description": "Radiation constant in cm^3/s", + "type": "number" + }, + "type": { + "title": "Type", + "default": "RadiativeRecombination", + "enum": [ + "RadiativeRecombination" + ], + "type": "string" + } + }, + "required": [ + "r_const" + ], + "additionalProperties": false + }, + "FossumCarrierLifetime": { + "title": "FossumCarrierLifetime", + "description": "Parameters for the Fossum carrier lifetime model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_300 : PositiveFloat\n [units = sec]. Carrier lifetime at 300K\nalpha_T : float\n Exponent for thermal dependence\nN0 : PositiveFloat\n [units = 1/cm^3]. Reference concentration\nA : float\n Constant A\nB : float\n Constant B\nC : float\n Constant C\nalpha : float\n Exponent constant\n\nNotes\n-----\n\n This model expresses the carrier lifetime as a function of the temperature and doping concentration.\n\n .. math::\n\n \\tau = \\frac{\\tau_{300} \\left( T/300 \\right)^\\alpha_T}{A + B (N/N_0) + C (N/N_0)^\\alpha}\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.FossumCarrierLifetime(\n ... tau_300=3.3e-6,\n ... alpha_T=-0.5,\n ... N0=7.1e15,\n ... A=1,\n ... B=0,\n ... C=1,\n ... alpha=1\n ... )\n\nReferences\n----------\n\n Fossum, J. G., and D. S. Lee. \"A physical model for the dependence of carrier lifetime on doping density in nondegenerate silicon.\" Solid-State Electronics 25.8 (1982): 741-747.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_300": { + "title": "Tau at 300K", + "description": "Carrier lifetime at 300K", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "alpha_T": { + "title": "Exponent for thermal dependence", + "description": "Exponent for thermal dependence", + "type": "number" + }, + "N0": { + "title": "Reference concentration", + "description": "Reference concentration", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "A": { + "title": "Constant A", + "description": "Constant A", + "type": "number" + }, + "B": { + "title": "Constant B", + "description": "Constant B", + "type": "number" + }, + "C": { + "title": "Constant C", + "description": "Constant C", + "type": "number" + }, + "alpha": { + "title": "Exponent constant", + "description": "Exponent constant", + "type": "number" + }, + "type": { + "title": "Type", + "default": "FossumCarrierLifetime", + "enum": [ + "FossumCarrierLifetime" + ], + "type": "string" + } + }, + "required": [ + "tau_300", + "alpha_T", + "N0", + "A", + "B", + "C", + "alpha" + ], + "additionalProperties": false + }, + "ShockleyReedHallRecombination": { + "title": "ShockleyReedHallRecombination", + "description": "Defines the parameters for the Shockley-Reed-Hall (SRH) recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_n : Union[PositiveFloat, FossumCarrierLifetime]\n Electron lifetime\ntau_p : Union[PositiveFloat, FossumCarrierLifetime]\n [units = sec]. Hole lifetime\n\nNotes\n-----\n\n The recombination rate parameter from this model is defined from [1]_ as follows:\n\n .. math::\n\n R_{SRH} = \\frac{n p - n_0 p_0}{\\tau_p \\left(n + \\sqrt{n_0 p_0}\\right) + \\tau_n \\left(p + \\sqrt{n_0 p_0}\\right)}.\n\n Note that the electron and holes densities are defined within the :class:`SemiconductorMedium`. The electron\n lifetime :math:`\\tau_n` and hole lifetimes :math:`\\tau_p` need to be defined.\n\n\n .. [1] Schenk. A model for the field and temperature dependence of shockley-read-hall\n lifetimes in silicon. Solid-State Electronics, 35:1585\u20131596, 1992.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6,\n ... )\n\nNote\n----\nImportant considerations when using this model:\n\n- Currently, lifetimes are considered constant (not dependent on temperature or doping).\n- This model represents mid-gap traps Shockley-Reed-Hall recombination.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_n": { + "title": "Electron lifetime", + "description": "Electron lifetime", + "union": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "tau_p": { + "title": "Hole lifetime", + "description": "Hole lifetime", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "type": { + "title": "Type", + "default": "ShockleyReedHallRecombination", + "enum": [ + "ShockleyReedHallRecombination" + ], + "type": "string" + } + }, + "required": [ + "tau_n", + "tau_p" + ], + "additionalProperties": false + }, + "SlotboomBandGapNarrowing": { + "title": "SlotboomBandGapNarrowing", + "description": "Parameters for the Slotboom model for band-gap narrowing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nv1 : PositiveFloat\n [units = V]. $V_{1,bgn}$ parameter\nn2 : PositiveFloat\n [units = 1/cm^3]. $N_{2,bgn}$ parameter\nc2 : float\n $C_{2,bgn}$ parameter\nmin_N : NonNegativeFloat\n [units = 1/cm^3]. Bandgap narrowing is applied at location where total doping is higher than 'min_N'.\n\nNotes\n------\n The Slotboom band-gap narrowing :math:`\\Delta E_G` model is discussed in [1]_ as follows:\n\n .. math::\n\n \\Delta E_G = V_{1,bgn} \\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right)\n + \\sqrt{\\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right) \\right)^2 + C_{2,bgn}} \\right)\n \\quad \\text{if} \\quad N_{tot} \\geq 10^{15} \\text{cm}^{-3},\n\n \\Delta E_G = 0 \\quad \\text{if} \\quad N_{tot} < 10^{15} \\text{cm}^{-3}.\n\n Note that :math:`N_{tot}` is the total doping as defined within a :class:`SemiconductorMedium`.\n\n Example\n -------\n >>> import tidy3d as td\n >>> default_Si = td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... )\n\n .. [1] 'UNIFIED APPARENT BANDGAP NARROWING IN n- AND p-TYPE SILICON' Solid-State Electronics Vol. 35, No. 2, pp. 125-129, 1992", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "v1": { + "title": "$V_{1,bgn}$ parameter", + "description": "$V_{1,bgn}$ parameter", + "units": "V", + "exclusiveMinimum": 0, + "type": "number" + }, + "n2": { + "title": "$N_{2,bgn}$ parameter", + "description": "$N_{2,bgn}$ parameter", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "c2": { + "title": "$C_{2,bgn}$ parameter", + "description": "$C_{2,bgn}$ parameter", + "type": "number" + }, + "min_N": { + "title": "Minimum total doping", + "description": "Bandgap narrowing is applied at location where total doping is higher than 'min_N'.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "SlotboomBandGapNarrowing", + "enum": [ + "SlotboomBandGapNarrowing" + ], + "type": "string" + } + }, + "required": [ + "v1", + "n2", + "c2", + "min_N" + ], + "additionalProperties": false + }, + "ConstantDoping": { + "title": "ConstantDoping", + "description": "Sets constant doping :math:`N` in the specified box with a :parameter`size` and :parameter:`concentration`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nconcentration : NonNegativeFloat = 0\n [units = 1/cm^3]. Doping concentration density in #/cm^3.\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> constant_box1 = td.ConstantDoping(center=(0, 0, 0), size=(2, 2, 2), concentration=1e18)\n>>> constant_box2 = td.ConstantDoping.from_bounds(rmin=box_coords[0], rmax=box_coords[1], concentration=1e18)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConstantDoping", + "enum": [ + "ConstantDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "concentration": { + "title": "Doping concentration density.", + "description": "Doping concentration density in #/cm^3.", + "default": 0, + "units": "1/cm^3", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "GaussianDoping": { + "title": "GaussianDoping", + "description": "Sets a gaussian doping in the specified box.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nref_con : PositiveFloat\n Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.\nconcentration : PositiveFloat\n The concentration at the center of the box.\nwidth : PositiveFloat\n Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. \nsource : str = xmin\n Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nNotes\n-----\nThe Gaussian doping concentration :math:`N` is defined in the following manner:\n\n- :math:`N=N_{\\text{max}}` at locations more than :math:``width`` um away from the sides of the box.\n- :math:`N=N_{\\text{ref}}` at location on the box sides.\n- a Gaussian variation between :math:`N_{\\text{max}}` and :math:`N_{\\text{ref}}` at locations less than ``width``\num away from the sides.\n\nBy definition, all sides of the box will have concentration :math:`N_{\\text{ref}}` (except the side specified\nas source) and the center of the box (``width`` away from the box sides) will have a concentration\n:math:`N_{\\text{max}}`.\n\n.. math::\n\n N = \\{N_{\\text{max}}\\} \\exp \\left[\n - \\ln \\left( \\frac{\\{N_{\\text{max}}\\}}{\\{N_{\\text{ref}}\\}} \\right)\n \\left( \\frac{(x|y|z) - \\{(x|y|z)_{\\text{box}}\\}}{\\text{width}} \\right)^2\n \\right]\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> gaussian_box1 = td.GaussianDoping(\n... center=(0, 0, 0),\n... size=(2, 2, 2),\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )\n>>> gaussian_box2 = td.GaussianDoping.from_bounds(\n... rmin=box_coords[0],\n... rmax=box_coords[1],\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GaussianDoping", + "enum": [ + "GaussianDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "ref_con": { + "title": "Reference concentration.", + "description": "Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concentration": { + "title": "Concentration", + "description": "The concentration at the center of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "width": { + "title": "Width of the gaussian.", + "description": "Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "source": { + "title": "Source face", + "description": "Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']", + "default": "xmin", + "type": "string" + } + }, + "required": [ + "size", + "ref_con", + "concentration", + "width" + ], + "additionalProperties": false + }, + "SemiconductorMedium": { + "title": "SemiconductorMedium", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "SemiconductorMedium", + "enum": [ + "SemiconductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "N_c": { + "title": "Effective density of electron states", + "description": "$N_c$ Effective density of states in the conduction band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "N_v": { + "title": "Effective density of hole states", + "description": "$N_v$ Effective density of states in the valence band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "E_g": { + "title": "Band-gap energy", + "description": "Band-gap energy", + "units": "eV", + "exclusiveMinimum": 0, + "type": "number" + }, + "mobility_n": { + "title": "Mobility model for electrons", + "description": "Mobility model for electrons", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "mobility_p": { + "title": "Mobility model for holes", + "description": "Mobility model for holes", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "R": { + "title": "Generation-Recombination models", + "description": "Array containing the R models to be applied to the material.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/AugerRecombination" + }, + { + "$ref": "#/definitions/RadiativeRecombination" + }, + { + "$ref": "#/definitions/ShockleyReedHallRecombination" + } + ] + } + }, + "delta_E_g": { + "title": "$\\Delta E_g$ Bandgap narrowing model.", + "description": "Bandgap narrowing model.", + "allOf": [ + { + "$ref": "#/definitions/SlotboomBandGapNarrowing" + } + ] + }, + "N_a": { + "title": "Doping: Acceptor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + }, + "N_d": { + "title": "Doping: Donor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + } + }, + "required": [ + "N_c", + "N_v", + "E_g", + "mobility_n", + "mobility_p" + ], + "additionalProperties": false + }, + "MultiPhysicsMedium": { + "title": "MultiPhysicsMedium", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Medium name", + "type": "string" + }, + "optical": { + "title": "Optical properties", + "description": "Specifies optical properties.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "heat": { + "title": "Heat properties", + "description": "Specifies properties for Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "charge": { + "title": "Charge properties", + "description": "Specifies properties for Charge simulations.", + "anyOf": [ + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "MultiPhysicsMedium", + "enum": [ + "MultiPhysicsMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Box": { + "title": "Box", + "description": "Rectangular prism.\n Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\n\nExample\n-------\n>>> b = Box(center=(1,2,3), size=(2,2,2))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Box", + "enum": [ + "Box" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "Sphere": { + "title": "Sphere", + "description": "Spherical geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nradius : NonNegativeFloat\n [units = um]. Radius of geometry.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\n\nExample\n-------\n>>> b = Sphere(center=(1,2,3), radius=2)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Sphere", + "enum": [ + "Sphere" + ], + "type": "string" + }, + "radius": { + "title": "Radius", + "description": "Radius of geometry.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "radius" + ], + "additionalProperties": false + }, + "Cylinder": { + "title": "Cylinder", + "description": "Cylindrical geometry with optional sidewall angle along axis\ndirection. When ``sidewall_angle`` is nonzero, the shape is a\nconical frustum or a cone.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> c = Cylinder(center=(1,2,3), radius=2, length=5, axis=2)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../../notebooks/THzDemultiplexerFilter.html>`_\n* `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Cylinder", + "enum": [ + "Cylinder" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([(0,0), (1,0), (1,1)])\n>>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolySlab", + "enum": [ + "PolySlab" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])\n>>> faces = np.array([[1, 2, 3], [0, 3, 2], [0, 1, 3], [0, 2, 1]])\n>>> stl_geom = TriangleMesh.from_vertices_faces(vertices, faces)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangleMesh", + "enum": [ + "TriangleMesh" + ], + "type": "string" + }, + "mesh_dataset": { + "title": "Surface mesh data", + "description": "Surface mesh data.", + "allOf": [ + { + "$ref": "#/definitions/TriangleMeshDataset" + } + ] + } + }, + "required": [ + "mesh_dataset" + ], + "additionalProperties": false + }, + "GeometryGroup": { + "title": "GeometryGroup", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GeometryGroup", + "enum": [ + "GeometryGroup" + ], + "type": "string" + }, + "geometries": { + "title": "Geometries", + "description": "Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + } + }, + "required": [ + "geometries" + ], + "additionalProperties": false + }, + "ClipOperation": { + "title": "ClipOperation", + "description": "Class representing the result of a set operation between geometries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\noperation : Literal['union', 'intersection', 'difference', 'symmetric_difference']\n Operation to be performed between geometries.\ngeometry_a : ForwardRef('annotate_type(GeometryType)')\n First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.\ngeometry_b : ForwardRef('annotate_type(GeometryType)')\n Second operand for the set operation. It can also be any geometry type.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ClipOperation", + "enum": [ + "ClipOperation" + ], + "type": "string" + }, + "operation": { + "title": "Operation Type", + "description": "Operation to be performed between geometries.", + "enum": [ + "union", + "intersection", + "difference", + "symmetric_difference" + ], + "type": "string" + }, + "geometry_a": { + "title": "Geometry A", + "description": "First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "geometry_b": { + "title": "Geometry B", + "description": "Second operand for the set operation. It can also be any geometry type.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + }, + "required": [ + "operation", + "geometry_a", + "geometry_b" + ], + "additionalProperties": false + }, + "Transformed": { + "title": "Transformed", + "description": "Class representing a transformed geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : ForwardRef('annotate_type(GeometryType)')\n Base geometry to be transformed.\ntransform : ArrayLike[dtype=float, ndim=2, shape=(4, 4)] = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]\n Transform matrix applied to the base geometry.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Transformed", + "enum": [ + "Transformed" + ], + "type": "string" + }, + "geometry": { + "title": "Geometry", + "description": "Base geometry to be transformed.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "transform": { + "title": "Transform", + "description": "Transform matrix applied to the base geometry.", + "default": [ + [ + 1.0, + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "type": "ArrayLike" + } + }, + "required": [ + "geometry" + ], + "additionalProperties": false + }, + "Structure": { + "title": "Structure", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, + "type": { + "title": "Type", + "default": "Structure", + "enum": [ + "Structure" + ], + "type": "string" + }, + "medium": { + "title": "Medium", + "description": "Defines the electromagnetic properties of the structure's medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + } + }, + "required": [ + "geometry", + "medium" + ], + "additionalProperties": false + }, + "HeatSource": { + "title": "HeatSource", + "description": "Adds a volumetric heat source (heat sink if negative values\nare provided) to specific structures in the scene.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = HeatSource(rate=1, structures=[\"box\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatSource", + "enum": [ + "HeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "HeatFromElectricSource": { + "title": "HeatFromElectricSource", + "description": "Volumetric heat source generated from an electric simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\n\nNotes\n-----\n\n If a :class`HeatFromElectricSource` is specified as a source, appropriate boundary\n conditions for an electric simulation must be provided, since such a simulation\n will be executed before the heat simulation can run.\n\nExample\n-------\n>>> heat_source = HeatFromElectricSource()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatFromElectricSource", + "enum": [ + "HeatFromElectricSource" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UniformHeatSource": { + "title": "UniformHeatSource", + "description": "Volumetric heat source. This class is deprecated. You can use\n'HeatSource' instead.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = UniformHeatSource(rate=1, structures=[\"box\"]) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "UniformHeatSource", + "enum": [ + "UniformHeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "StructureBoundary": { + "title": "StructureBoundary", + "description": "Placement of boundary conditions on the structure's boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\n\nExample\n-------\n>>> bc_placement = StructureBoundary(structure=\"box\")", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureBoundary", + "enum": [ + "StructureBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "StructureStructureInterface": { + "title": "StructureStructureInterface", + "description": "Placement of boundary conditions between two structures.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructures : Tuple[str, str]\n Names of two structures.\n\nExample\n-------\n>>> bc_placement = StructureStructureInterface(structures=[\"box\", \"sphere\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureStructureInterface", + "enum": [ + "StructureStructureInterface" + ], + "type": "string" + }, + "structures": { + "title": "Structures", + "description": "Names of two structures.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "structures" + ], + "additionalProperties": false + }, + "MediumMediumInterface": { + "title": "MediumMediumInterface", + "description": "Placement of boundary conditions between two mediums.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmediums : Tuple[str, str]\n Names of two mediums.\n\nExample\n-------\n>>> bc_placement = MediumMediumInterface(mediums=[\"dieletric\", \"metal\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "MediumMediumInterface", + "enum": [ + "MediumMediumInterface" + ], + "type": "string" + }, + "mediums": { + "title": "Mediums", + "description": "Names of two mediums.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "mediums" + ], + "additionalProperties": false + }, + "SimulationBoundary": { + "title": "SimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = SimulationBoundary(surfaces=[\"x-\", \"x+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SimulationBoundary", + "enum": [ + "SimulationBoundary" + ], + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "additionalProperties": false + }, + "StructureSimulationBoundary": { + "title": "StructureSimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary covered by the structure.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = StructureSimulationBoundary(structure=\"box\", surfaces=[\"y-\", \"y+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureSimulationBoundary", + "enum": [ + "StructureSimulationBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "TemperatureBC": { + "title": "TemperatureBC", + "description": "Constant temperature thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat\n [units = K]. Temperature value in units of K.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.TemperatureBC(temperature=300)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureBC", + "enum": [ + "TemperatureBC" + ], + "type": "string" + }, + "temperature": { + "title": "Temperature", + "description": "Temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "temperature" + ], + "additionalProperties": false + }, + "HeatFluxBC": { + "title": "HeatFluxBC", + "description": "Constant flux thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nflux : float\n [units = W/um^2]. Heat flux value in units of W/um^2.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.HeatFluxBC(flux=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatFluxBC", + "enum": [ + "HeatFluxBC" + ], + "type": "string" + }, + "flux": { + "title": "Heat Flux", + "description": "Heat flux value in units of W/um^2.", + "units": "W/um^2", + "type": "number" + } + }, + "required": [ + "flux" + ], + "additionalProperties": false + }, + "ConvectionBC": { + "title": "ConvectionBC", + "description": "Convective thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nambient_temperature : PositiveFloat\n [units = K]. Ambient temperature value in units of K.\ntransfer_coeff : NonNegativeFloat\n [units = W/(um^2*K)]. Heat flux value in units of W/(um^2*K).\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.ConvectionBC(ambient_temperature=300, transfer_coeff=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConvectionBC", + "enum": [ + "ConvectionBC" + ], + "type": "string" + }, + "ambient_temperature": { + "title": "Ambient Temperature", + "description": "Ambient temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "transfer_coeff": { + "title": "Heat Transfer Coefficient", + "description": "Heat flux value in units of W/(um^2*K).", + "units": "W/(um^2*K)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "ambient_temperature", + "transfer_coeff" + ], + "additionalProperties": false + }, + "DCVoltageSource": { + "title": "DCVoltageSource", + "description": "DC voltage source in volts.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n voltage : ArrayLike[dtype=float, ndim=1]\n [units = V]. DC voltage usually used as source in 'VoltageBC' boundary conditions.\nunits : Literal['V'] = V\n \nNotes\n-----\n\n This voltage refers to potential above the equivalent simulation ground. Currently, electrical ports\n are not defined.\n\nExamples\n--------\n>>> import tidy3d as td\n>>> voltages = [-0.5, 0, 1, 2, 3, 4]\n>>> voltage_source = td.DCVoltageSource(voltage=voltages)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "voltage": { + "title": "Voltage", + "description": "DC voltage usually used as source in 'VoltageBC' boundary conditions.", + "units": "V", + "type": "ArrayLike" + }, + "units": { + "title": "Units", + "default": "V", + "enum": [ + "V" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCVoltageSource", + "enum": [ + "DCVoltageSource" + ], + "type": "string" + } + }, + "required": [ + "voltage" + ], + "additionalProperties": false + }, + "VoltageBC": { + "title": "VoltageBC", + "description": "Constant electric potential (voltage) :math:`= \\text{V}` boundary condition.\nSets a potential at the specified boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCVoltageSource\n [units = V]. Electric potential to be applied at the specified boundary.\n\nNotes\n-----\n\n In charge simulations it also accepts an array of voltages.\n In this case, a solution for each of these voltages will\n be computed.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_source = td.DCVoltageSource(voltage=1)\n>>> voltage_bc = td.VoltageBC(source=voltage_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VoltageBC", + "enum": [ + "VoltageBC" + ], + "type": "string" + }, + "source": { + "title": "Voltage", + "description": "Electric potential to be applied at the specified boundary.", + "units": "V", + "allOf": [ + { + "$ref": "#/definitions/DCVoltageSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "DCCurrentSource": { + "title": "DCCurrentSource", + "description": "DC current source in amperes.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n current : FiniteFloat\n [units = A]. DC current usually used as source in 'CurrentBC' boundary conditions.\nunits : Literal['A'] = A\n \nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=0.4)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "current": { + "title": "Current", + "description": "DC current usually used as source in 'CurrentBC' boundary conditions.", + "units": "A", + "type": "number" + }, + "units": { + "title": "Units", + "default": "A", + "enum": [ + "A" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCCurrentSource", + "enum": [ + "DCCurrentSource" + ], + "type": "string" + } + }, + "required": [ + "current" + ], + "additionalProperties": false + }, + "CurrentBC": { + "title": "CurrentBC", + "description": "Current boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCCurrentSource\n [units = A/um^2]. A current source\n\nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=1)\n>>> current_bc = CurrentBC(source=current_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CurrentBC", + "enum": [ + "CurrentBC" + ], + "type": "string" + }, + "source": { + "title": "Current Source", + "description": "A current source", + "units": "A/um^2", + "allOf": [ + { + "$ref": "#/definitions/DCCurrentSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "InsulatingBC": { + "title": "InsulatingBC", + "description": "Insulation boundary condition.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNotes\n-----\n\n Ensures the electric potential to the normal :math:`\\nabla \\psi \\cdot \\mathbf{n} = 0` as well as the\n surface recombination current density :math:`J_s = \\mathbf{J} \\cdot \\mathbf{n} = 0` are set to zero where\n the current density is :math:`\\mathbf{J_n}` and the normal vector is :math:`\\mathbf{n}`\n\nExample\n-------\n>>> bc = InsulatingBC()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "InsulatingBC", + "enum": [ + "InsulatingBC" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "HeatChargeBoundarySpec": { + "title": "HeatChargeBoundarySpec", + "description": "Heat-Charge boundary conditions specification.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc_v1 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),\n... placement=td.StructureBoundary(structure=\"contact_left\"),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatChargeBoundarySpec", + "enum": [ + "HeatChargeBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "HeatBoundarySpec": { + "title": "HeatBoundarySpec", + "description": "Heat BC specification. DEPRECIATED.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nWarning\n-------\n Included backward-compatibility only.\n\nExample\n--------\n>>> import tidy3d as td\n>>> bc_spec = td.HeatBoundarySpec(\n... placement=td.SimulationBoundary(),\n... condition=td.ConvectionBC(ambient_temperature=300, transfer_coeff=1),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatBoundarySpec", + "enum": [ + "HeatBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "TemperatureMonitor": { + "title": "TemperatureMonitor", + "description": "Temperature monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\ninterval : PositiveInt = 1\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureMonitor", + "enum": [ + "TemperatureMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + }, + "interval": { + "title": "Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyPotentialMonitor": { + "title": "SteadyPotentialMonitor", + "description": "Electric potential (:math:`\\psi`) monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyPotentialMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyPotentialMonitor", + "enum": [ + "SteadyPotentialMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyFreeCarrierMonitor": { + "title": "SteadyFreeCarrierMonitor", + "description": "Free-carrier monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyFreeCarrierMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyFreeCarrierMonitor", + "enum": [ + "SteadyFreeCarrierMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyEnergyBandMonitor": { + "title": "SteadyEnergyBandMonitor", + "description": "Energy bands monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> energy_monitor_z0 = td.SteadyEnergyBandMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"bands_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyEnergyBandMonitor", + "enum": [ + "SteadyEnergyBandMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyElectricFieldMonitor": { + "title": "SteadyElectricFieldMonitor", + "description": "Electric field monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> electric_field_monitor_z0 = td.SteadyElectricFieldMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"electric_field_z0\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyElectricFieldMonitor", + "enum": [ + "SteadyElectricFieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyCapacitanceMonitor": { + "title": "SteadyCapacitanceMonitor", + "description": "Capacitance monitor associated with a charge simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> capacitance_global_mnt = td.SteadyCapacitanceMonitor(\n... center=(0, 0.14, 0), size=(td.inf, td.inf, 0), name=\"capacitance_global_mnt\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyCapacitanceMonitor", + "enum": [ + "SteadyCapacitanceMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "UniformUnstructuredGrid": { + "title": "UniformUnstructuredGrid", + "description": "Uniform grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\nmin_edges_per_circumference : PositiveFloat = 15\n Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.\nmin_edges_per_side : PositiveFloat = 2\n Enforced minimum number of mesh segments per any side of an object.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.\n\nExample\n-------\n>>> heat_grid = UniformUnstructuredGrid(dl=0.1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "UniformUnstructuredGrid", + "enum": [ + "UniformUnstructuredGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_circumference": { + "title": "Minimum Edges per Circumference", + "description": "Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.", + "default": 15, + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_side": { + "title": "Minimum Edges per Side", + "description": "Enforced minimum number of mesh segments per any side of an object.", + "default": 2, + "exclusiveMinimum": 0, + "type": "number" + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GridRefinementRegion": { + "title": "GridRefinementRegion", + "description": "Refinement region for the unstructured mesh. The cell size is enforced to be constant inside the region.\nThe cell size outside of the region depends on the distance from the region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\ndl_internal : PositiveFloat\n [units = um]. Mesh cell size inside the refinement region\ntransition_thickness : NonNegativeFloat\n [units = um]. Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GridRefinementRegion", + "enum": [ + "GridRefinementRegion" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "dl_internal": { + "title": "Internal mesh cell size", + "description": "Mesh cell size inside the refinement region", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "transition_thickness": { + "title": "Interface Distance", + "description": "Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "units": "um", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "dl_internal", + "transition_thickness" + ], + "additionalProperties": false + }, + "GridRefinementLine": { + "title": "GridRefinementLine", + "description": "Refinement line for the unstructured mesh. The cell size depends on the distance from the line.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr1 : Tuple[float, float, float]\n [units = um]. Start point of the line in x, y, and z.\nr2 : Tuple[float, float, float]\n [units = um]. End point of the line in x, y, and z.\ndl_near : PositiveFloat\n [units = um]. Mesh cell size near the line\ndistance_near : NonNegativeFloat\n [units = um]. Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r1": { + "title": "Start point of the line", + "description": "Start point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "r2": { + "title": "End point of the line", + "description": "End point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "dl_near": { + "title": "Mesh cell size near the line", + "description": "Mesh cell size near the line", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_near": { + "title": "Near distance", + "description": "Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk distance", + "description": "Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "GridRefinementLine", + "enum": [ + "GridRefinementLine" + ], + "type": "string" + } + }, + "required": [ + "r1", + "r2", + "dl_near", + "distance_near", + "distance_bulk" + ], + "additionalProperties": false + }, + "DistanceUnstructuredGrid": { + "title": "DistanceUnstructuredGrid", + "description": "Adaptive grid based on distance to material interfaces. Currently not recommended for larger\nsimulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl_interface : PositiveFloat\n [units = um]. Grid size near material interfaces.\ndl_bulk : PositiveFloat\n [units = um]. Grid size away from material interfaces.\ndistance_interface : NonNegativeFloat\n [units = um]. Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.\nsampling : PositiveFloat = 100\n An internal advanced parameter that defines number of sampling points per surface when computing distance values.\nuniform_grid_mediums : Tuple[str, ...] = ()\n List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.\nmesh_refinements : Tuple[Annotated[Union[tidy3d.components.tcad.grid.GridRefinementRegion, tidy3d.components.tcad.grid.GridRefinementLine], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of regions/lines for which the mesh refinement will be applied\n\nExample\n-------\n>>> heat_grid = DistanceUnstructuredGrid(\n... dl_interface=0.1,\n... dl_bulk=1,\n... distance_interface=0.3,\n... distance_bulk=2,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "DistanceUnstructuredGrid", + "enum": [ + "DistanceUnstructuredGrid" + ], + "type": "string" + }, + "dl_interface": { + "title": "Interface Grid Size", + "description": "Grid size near material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl_bulk": { + "title": "Bulk Grid Size", + "description": "Grid size away from material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_interface": { + "title": "Interface Distance", + "description": "Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk Distance", + "description": "Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "sampling": { + "title": "Surface Sampling", + "description": "An internal advanced parameter that defines number of sampling points per surface when computing distance values.", + "default": 100, + "exclusiveMinimum": 0, + "type": "number" + }, + "uniform_grid_mediums": { + "title": "Mediums With Uniform Refinement", + "description": "List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "mesh_refinements": { + "title": "Mesh refinement structures", + "description": "List of regions/lines for which the mesh refinement will be applied", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "GridRefinementRegion": "#/definitions/GridRefinementRegion", + "GridRefinementLine": "#/definitions/GridRefinementLine" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GridRefinementRegion" + }, + { + "$ref": "#/definitions/GridRefinementLine" + } + ] + } + } + }, + "required": [ + "dl_interface", + "dl_bulk", + "distance_interface", + "distance_bulk" + ], + "additionalProperties": false + }, + "ChargeToleranceSpec": { + "title": "ChargeToleranceSpec", + "description": "Charge tolerance parameters relevant to multiple simulation analysis types.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nabs_tol : PositiveFloat = 10000000000.0\n Absolute tolerance used as stop criteria when converging towards a solution.\nrel_tol : PositiveFloat = 1e-10\n Relative tolerance used as stop criteria when converging towards a solution.\nmax_iters : PositiveInt = 30\n Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.\nramp_up_iters : PositiveInt = 1\n In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.\n\nExample\n-------\n>>> import tidy3d as td\n>>> charge_settings = td.ChargeToleranceSpec(abs_tol=1e8, rel_tol=1e-10, max_iters=30)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "abs_tol": { + "title": "Absolute tolerance.", + "description": "Absolute tolerance used as stop criteria when converging towards a solution.", + "default": 10000000000.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "rel_tol": { + "title": "Relative tolerance.", + "description": "Relative tolerance used as stop criteria when converging towards a solution.", + "default": 1e-10, + "exclusiveMinimum": 0, + "type": "number" + }, + "max_iters": { + "title": "Maximum number of iterations.", + "description": "Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.", + "default": 30, + "exclusiveMinimum": 0, + "type": "integer" + }, + "ramp_up_iters": { + "title": "Ramp-up iterations.", + "description": "In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "ChargeToleranceSpec", + "enum": [ + "ChargeToleranceSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IsothermalSteadyChargeDCAnalysis": { + "title": "IsothermalSteadyChargeDCAnalysis", + "description": "Configures relevant steady-state DC simulation parameters for a charge simulation.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat = 300\n [units = K]. Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.\ntolerance_settings : ChargeToleranceSpec = ChargeToleranceSpec(attrs={}, abs_tol=10000000000.0, rel_tol=1e-10, max_iters=30, ramp_up_iters=1, type='ChargeToleranceSpec')\n convergence_dv : PositiveFloat = 1.0\n By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.\nfermi_dirac : bool = False\n Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "temperature": { + "title": "Temperature", + "description": "Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.", + "default": 300, + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "tolerance_settings": { + "title": "Tolerance settings", + "default": { + "attrs": {}, + "abs_tol": 10000000000.0, + "rel_tol": 1e-10, + "max_iters": 30, + "ramp_up_iters": 1, + "type": "ChargeToleranceSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ChargeToleranceSpec" + } + ] + }, + "convergence_dv": { + "title": "Bias step.", + "description": "By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.", + "default": 1.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "fermi_dirac": { + "title": "Fermi-Dirac statistics", + "description": "Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "default": false, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "IsothermalSteadyChargeDCAnalysis", + "enum": [ + "IsothermalSteadyChargeDCAnalysis" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UnsteadySpec": { + "title": "UnsteadySpec", + "description": "Defines an unsteady specification\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntime_step : PositiveFloat\n [units = sec]. Time step taken for each iteration of the time integration loop.\ntotal_time_steps : PositiveInt\n Specifies the total number of time steps run during the simulation.\n\nExample\n--------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "time_step": { + "title": "Time-step", + "description": "Time step taken for each iteration of the time integration loop.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "total_time_steps": { + "title": "Total time steps", + "description": "Specifies the total number of time steps run during the simulation.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "UnsteadySpec", + "enum": [ + "UnsteadySpec" + ], + "type": "string" + } + }, + "required": [ + "time_step", + "total_time_steps" + ], + "additionalProperties": false + }, + "UnsteadyHeatAnalysis": { + "title": "UnsteadyHeatAnalysis", + "description": "Configures relevant unsteady-state heat simulation parameters.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ninitial_temperature : PositiveFloat\n [units = K]. Initial value for the temperature field.\nunsteady_spec : UnsteadySpec\n Time step and total time steps for the unsteady simulation.\n\nExample\n-------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadyHeatAnalysis(\n... initial_temperature=300,\n... unsteady_spec=td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... ),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "initial_temperature": { + "title": "Initial temperature.", + "description": "Initial value for the temperature field.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "unsteady_spec": { + "title": "Unsteady specification", + "description": "Time step and total time steps for the unsteady simulation.", + "allOf": [ + { + "$ref": "#/definitions/UnsteadySpec" + } + ] + }, + "type": { + "title": "Type", + "default": "UnsteadyHeatAnalysis", + "enum": [ + "UnsteadyHeatAnalysis" + ], + "type": "string" + } + }, + "required": [ + "initial_temperature", + "unsteady_spec" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/ModeSimulation.json b/schemas/ModeSimulation.json new file mode 100644 index 0000000000..45744c16e5 --- /dev/null +++ b/schemas/ModeSimulation.json @@ -0,0 +1,13206 @@ +{ + "title": "ModeSimulation", + "description": "Simulation class for solving electromagnetic eigenmodes in a 2D plane with\ntranslational invariance in the third dimension. If the field ``plane`` is\nspecified, the domain for mode solving is the intersection between the ``plane``\nand the simulation geometry. If the simulation geometry is 2D (has zero size\nin one dimension) and the ``plane`` is ``None``, then the domain for mode solving\nis the entire 2D geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. \nsources : Tuple[] = ()\n Sources in the simulation. Note: sources are not supported in mode simulations.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), y=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), z=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides. This behavior is for consistency with FDTD simulations; however, please note that the mode solver terminates the mode plane with PEC boundary. The 'ModeSpec' can be used to apply PML layers in the mode solver.\nmonitors : Tuple[PermittivityMonitor, ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.\nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\nmode_spec : ModeSpec\n Container with specifications about the modes to be solved for.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n A list of frequencies at which to solve.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\nplane : Union[Box, ModeSource, ModeMonitor, ModeSolverMonitor] = None\n Cross-sectional plane in which the mode will be computed. If provided, the computational domain will be the intersection between the provided ``plane`` and the simulation geometry. If ``None``, the simulation must be 2D, and the plane will be the entire simulation geometry.\n\nThe ``symmetry`` field can be used to enforce reflection symmetry across planes\nthrough the ``center`` of the simulation. Each component of the ``symmetry`` field\nis only used if the ``center`` of the ``plane`` and the simulation geometry\ncoincide in that component. Symmetry normal to the mode solving domain has no\neffect; the field ``filter_pol`` in :class:`.ModeSpec` can be used here instead.\n\nExample\n-------\n>>> from tidy3d import C_0, ModeSpec, BoundarySpec, Boundary\n>>> lambda0 = 1550e-9\n>>> freq0 = C_0 / lambda0\n>>> freqs = [freq0]\n>>> sim_size = lambda0, lambda0, 0\n>>> mode_spec = ModeSpec(num_modes=4)\n>>> boundary_spec = BoundarySpec(\n... x=Boundary.pec(),\n... y=Boundary.pec(),\n... z=Boundary.periodic()\n... )\n>>> sim = ModeSimulation(\n... size=sim_size,\n... freqs=freqs,\n... mode_spec=mode_spec,\n... boundary_spec=boundary_spec\n... )\n\nSee Also\n--------\n\n:class:`ModeSource`:\n Injects current source to excite modal profile on finite extent plane.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeSimulation", + "enum": [ + "ModeSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to vacuum if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. ", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Sources", + "description": "Sources in the simulation. Note: sources are not supported in mode simulations.", + "default": [], + "type": "array", + "minItems": 0, + "maxItems": 0 + }, + "boundary_spec": { + "title": "Boundaries", + "description": "Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides. This behavior is for consistency with FDTD simulations; however, please note that the mode solver terminates the mode plane with PEC boundary. The 'ModeSpec' can be used to apply PML layers in the mode solver.", + "default": { + "attrs": {}, + "x": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "y": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "z": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "type": "BoundarySpec" + }, + "allOf": [ + { + "$ref": "#/definitions/BoundarySpec" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/PermittivityMonitor" + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Specifications for the simulation grid along each of the three directions.", + "default": { + "attrs": {}, + "grid_x": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_y": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_z": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "wavelength": null, + "override_structures": [], + "snapping_points": [], + "layer_refinement_specs": [], + "type": "GridSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/GridSpec" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "lumped_elements": { + "title": "Lumped Elements", + "description": "Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "LumpedResistor": "#/definitions/LumpedResistor", + "CoaxialLumpedResistor": "#/definitions/CoaxialLumpedResistor", + "LinearLumpedElement": "#/definitions/LinearLumpedElement" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LumpedResistor" + }, + { + "$ref": "#/definitions/CoaxialLumpedResistor" + }, + { + "$ref": "#/definitions/LinearLumpedElement" + } + ] + } + }, + "subpixel": { + "title": "Subpixel Averaging", + "description": "Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.", + "default": { + "attrs": {}, + "dielectric": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "metal": { + "attrs": {}, + "type": "Staircasing" + }, + "pec": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" + }, + "lossy_metal": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "type": "SubpixelSpec" + }, + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/SubpixelSpec" + } + ] + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.", + "default": "tidy3d", + "enum": [ + "autograd_fwd", + "autograd_bwd", + "tidy3d" + ], + "type": "string" + }, + "post_norm": { + "title": "Post Normalization Values", + "description": "Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.", + "default": 1.0, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "mode_spec": { + "title": "Mode specification", + "description": "Container with specifications about the modes to be solved for.", + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "freqs": { + "title": "Frequencies", + "description": "A list of frequencies at which to solve.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "direction": { + "title": "Propagation direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "colocate": { + "title": "Colocate fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.", + "default": true, + "type": "boolean" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "plane": { + "title": "Plane", + "description": "Cross-sectional plane in which the mode will be computed. If provided, the computational domain will be the intersection between the provided ``plane`` and the simulation geometry. If ``None``, the simulation must be 2D, and the plane will be the entire simulation geometry.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "ModeSource": "#/definitions/ModeSource", + "ModeMonitor": "#/definitions/ModeMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/ModeSource" + }, + { + "$ref": "#/definitions/ModeMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + } + ] + } + }, + "required": [ + "size", + "mode_spec", + "freqs" + ], + "additionalProperties": false, + "definitions": { + "NonlinearSusceptibility": { + "title": "NonlinearSusceptibility", + "description": "Model for an instantaneous nonlinear chi3 susceptibility.\nThe expression for the instantaneous nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nchi3 : float = 0\n [units = um^2 / V^2]. Chi3 nonlinear susceptibility.\nnumiters : Optional[PositiveInt] = None\n Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\chi_3` must be real.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "NonlinearSusceptibility", + "enum": [ + "NonlinearSusceptibility" + ], + "type": "string" + }, + "chi3": { + "title": "Chi3", + "description": "Chi3 nonlinear susceptibility.", + "default": 0, + "units": "um^2 / V^2", + "type": "number" + }, + "numiters": { + "title": "Number of iterations", + "description": "Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.", + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "additionalProperties": false + }, + "ComplexNumber": { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + "TwoPhotonAbsorption": { + "title": "TwoPhotonAbsorption", + "description": "Model for two-photon absorption (TPA) nonlinearity which gives an intensity-dependent\nabsorption of the form :math:`\\alpha = \\alpha_0 + \\beta I`.\nAlso includes free-carrier absorption (FCA) and free-carrier plasma dispersion (FCPD) effects.\nThe expression for the nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nbeta : Union[float, tidycomplex, ComplexNumber] = 0\n [units = um / W]. Coefficient for two-photon absorption (TPA).\ntau : NonNegativeFloat = 0\n [units = sec]. Lifetime for the free carriers created by two-photon absorption (TPA).\nsigma : NonNegativeFloat = 0\n [units = um^2]. Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.\ne_e : NonNegativeFloat = 1\n Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\ne_h : NonNegativeFloat = 1\n Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_e : float = 0\n [units = um^(3 e_e)]. Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_h : float = 0\n [units = um^(3 e_h)]. Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\nfreq0 : Optional[PositiveFloat] = None\n Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\beta` must be real.\n\n .. math::\n\n P_{NL} = P_{TPA} + P_{FCA} + P_{FCPD} \\\\\n P_{TPA} = -\\frac{4}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{2 i \\omega} |E|^2 E \\\\\n P_{FCA} = -\\frac{c_0 \\varepsilon_0 n_0 \\sigma N_f}{i \\omega} E \\\\\n \\frac{dN_f}{dt} = \\frac{8}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{8 q_e \\hbar \\omega} |E|^4 - \\frac{N_f}{\\tau} \\\\\n N_e = N_h = N_f \\\\\n P_{FCPD} = \\varepsilon_0 2 n_0 \\Delta n (N_f) E \\\\\n \\Delta n (N_f) = (c_e N_e^{e_e} + c_h N_h^{e_h})\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n The implementation is described in::\n\n N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si\n High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> tpa_model = TwoPhotonAbsorption(beta=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TwoPhotonAbsorption", + "enum": [ + "TwoPhotonAbsorption" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "beta": { + "title": "TPA coefficient", + "description": "Coefficient for two-photon absorption (TPA).", + "default": 0, + "units": "um / W", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "tau": { + "title": "Carrier lifetime", + "description": "Lifetime for the free carriers created by two-photon absorption (TPA).", + "default": 0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "sigma": { + "title": "FCA cross section", + "description": "Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.", + "default": 0, + "units": "um^2", + "minimum": 0, + "type": "number" + }, + "e_e": { + "title": "Electron exponent", + "description": "Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "e_h": { + "title": "Hole exponent", + "description": "Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "c_e": { + "title": "Electron coefficient", + "description": "Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_e)", + "type": "number" + }, + "c_h": { + "title": "Hole coefficient", + "description": "Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_h)", + "type": "number" + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "freq0": { + "title": "Central frequency", + "description": "Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "KerrNonlinearity": { + "title": "KerrNonlinearity", + "description": "Model for Kerr nonlinearity which gives an intensity-dependent refractive index\nof the form :math:`n = n_0 + n_2 I`. The expression for the nonlinear polarization\nis given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nn2 : Union[tidycomplex, ComplexNumber] = 0\n [units = um^2 / W]. Nonlinear refractive index in the Kerr nonlinearity.\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\n_2` must be real.\n\n This model is equivalent to a :class:`.NonlinearSusceptibility`; the\n relation between the parameters is given below.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E \\\\\n n_2 = \\frac{3}{4 n_0^2 \\varepsilon_0 c_0} \\chi_3\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n To simulate nonlinear loss, consider instead using a :class:`.TwoPhotonAbsorption`\n model, which implements a more physical dispersive loss of the form\n :math:`\\chi_{TPA} = i \\frac{c_0 n_0 \\beta}{\\omega} I`.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> kerr_model = KerrNonlinearity(n2=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "KerrNonlinearity", + "enum": [ + "KerrNonlinearity" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "n2": { + "title": "Nonlinear refractive index", + "description": "Nonlinear refractive index in the Kerr nonlinearity.", + "default": 0, + "units": "um^2 / W", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "additionalProperties": false + }, + "NonlinearSpec": { + "title": "NonlinearSpec", + "description": "Abstract specification for adding nonlinearities to a medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmodels : Tuple[Union[NonlinearSusceptibility, TwoPhotonAbsorption, KerrNonlinearity], ...] = ()\n The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.\nnum_iters : PositiveInt = 5\n Number of iterations for solving nonlinear constitutive relation.\n\nNote\n----\nThe nonlinear constitutive relation is solved iteratively; it may not converge\nfor strong nonlinearities. Increasing ``num_iters`` can help with convergence.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)\n>>> nonlinear_spec = NonlinearSpec(models=[nonlinear_susceptibility])\n>>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "models": { + "title": "Nonlinear models", + "description": "The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSusceptibility" + }, + { + "$ref": "#/definitions/TwoPhotonAbsorption" + }, + { + "$ref": "#/definitions/KerrNonlinearity" + } + ] + } + }, + "num_iters": { + "title": "Number of iterations", + "description": "Number of iterations for solving nonlinear constitutive relation.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "NonlinearSpec", + "enum": [ + "NonlinearSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SpaceModulation": { + "title": "SpaceModulation", + "description": "The modulation profile with a user-supplied spatial distribution of\namplitude and phase.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : Union[float, SpatialDataArray] = 1\n Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.\nphase : Union[float, SpatialDataArray] = 0\n [units = rad]. Phase of modulation that can vary spatially.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Method of interpolation to use to obtain values at spatial locations on the Yee grids.\n\nNote\n----\n.. math::\n\n amp\\_space(r) = amplitude(r) \\cdot e^{i \\cdot phase(r)}\n\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> amp = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> phase = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> space = SpaceModulation(amplitude=amp, phase=phase)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SpaceModulation", + "enum": [ + "SpaceModulation" + ], + "type": "string" + }, + "amplitude": { + "title": "Amplitude of modulation in space", + "description": "Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.", + "default": 1, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "phase": { + "title": "Phase of modulation in space", + "description": "Phase of modulation that can vary spatially.", + "default": 0, + "units": "rad", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Method of interpolation to use to obtain values at spatial locations on the Yee grids.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContinuousWaveTimeModulation": { + "title": "ContinuousWaveTimeModulation", + "description": "Class describing modulation with a harmonic time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Modulation frequency.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t}\n\nNote\n----\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\n\nExample\n-------\n>>> cw = ContinuousWaveTimeModulation(freq0=200e12, amplitude=1, phase=0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWaveTimeModulation", + "enum": [ + "ContinuousWaveTimeModulation" + ], + "type": "string" + }, + "freq0": { + "title": "Modulation Frequency", + "description": "Modulation frequency.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "freq0" + ], + "additionalProperties": false + }, + "SpaceTimeModulation": { + "title": "SpaceTimeModulation", + "description": "Space-time modulation applied to a medium, adding\non top of the time-independent part.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nspace_modulation : SpaceModulation = SpaceModulation(attrs={}, type='SpaceModulation', amplitude=1.0, phase=0.0, interp_method='nearest')\n Space modulation part from the separable SpaceTimeModulation.\ntime_modulation : ContinuousWaveTimeModulation\n Time modulation part from the separable SpaceTimeModulation.\n\n\nNote\n----\nThe space-time modulation must be separable in space and time.\ne.g. when applied to permittivity,\n\n.. math::\n\n \\delta \\epsilon(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "space_modulation": { + "title": "Space modulation", + "description": "Space modulation part from the separable SpaceTimeModulation.", + "default": { + "attrs": {}, + "type": "SpaceModulation", + "amplitude": 1.0, + "phase": 0.0, + "interp_method": "nearest" + }, + "allOf": [ + { + "$ref": "#/definitions/SpaceModulation" + } + ] + }, + "time_modulation": { + "title": "Time modulation", + "description": "Time modulation part from the separable SpaceTimeModulation.", + "allOf": [ + { + "$ref": "#/definitions/ContinuousWaveTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "SpaceTimeModulation", + "enum": [ + "SpaceTimeModulation" + ], + "type": "string" + } + }, + "required": [ + "time_modulation" + ], + "additionalProperties": false + }, + "ModulationSpec": { + "title": "ModulationSpec", + "description": "Specification adding space-time modulation to the non-dispersive part of medium\nincluding relative permittivity at infinite frequency and electric conductivity.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npermittivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.\nconductivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of electric conductivity applied on top of the base conductivity.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "permittivity": { + "title": "Space-time modulation of relative permittivity", + "description": "Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "conductivity": { + "title": "Space-time modulation of conductivity", + "description": "Space-time modulation of electric conductivity applied on top of the base conductivity.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "ModulationSpec", + "enum": [ + "ModulationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VisualizationSpec": { + "title": "VisualizationSpec", + "description": "Defines specification for visualization when used with plotting functions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfacecolor : str = \n Color applied to the faces in visualization.\nedgecolor : Optional[str] = \n Color applied to the edges in visualization.\nalpha : Optional[ConstrainedFloatValue] = 1.0\n Opacity/alpha value in plotting between 0 and 1.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "facecolor": { + "title": "Face color", + "description": "Color applied to the faces in visualization.", + "default": "", + "type": "string" + }, + "edgecolor": { + "title": "Edge color", + "description": "Color applied to the edges in visualization.", + "default": "", + "type": "string" + }, + "alpha": { + "title": "Opacity", + "description": "Opacity/alpha value in plotting between 0 and 1.", + "default": 1.0, + "minimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "VisualizationSpec", + "enum": [ + "VisualizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FluidSpec": { + "title": "FluidSpec", + "description": "Fluid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidSpec", + "enum": [ + "FluidSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SolidSpec": { + "title": "SolidSpec", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidSpec", + "enum": [ + "SolidSpec" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "SolidMedium": { + "title": "SolidMedium", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidMedium", + "enum": [ + "SolidMedium" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "FluidMedium": { + "title": "FluidMedium", + "description": "Fluid medium. Heat simulations will not solve for temperature\nin a structure that has a medium with this 'heat_spec'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\n\nExample\n-------\n>>> solid = FluidMedium()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidMedium", + "enum": [ + "FluidMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Medium": { + "title": "Medium", + "description": "Dispersionless medium. Mediums define the optical properties of the materials within the simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n In a dispersion-less medium, the displacement field :math:`D(t)` reacts instantaneously to the applied\n electric field :math:`E(t)`.\n\n .. math::\n\n D(t) = \\epsilon E(t)\n\nExample\n-------\n>>> dielectric = Medium(permittivity=4.0, name='my_medium')\n>>> eps = dielectric.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Introduction on Tidy3D working principles <../../notebooks/Primer.html#Mediums>`_\n * `Index <../../notebooks/docs/features/medium.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_\n\n**GUI**\n * `Mediums `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium", + "enum": [ + "Medium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "additionalProperties": false + }, + "HammerstadSurfaceRoughness": { + "title": "HammerstadSurfaceRoughness", + "description": "Modified Hammerstad surface roughness model. It's a popular model that works well\nunder 5 GHz for surface roughness below 2 micrometer RMS.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrq : PositiveFloat\n [units = um]. RMS peak-to-valley height (Rq) of the surface roughness.\nroughness_factor : ConstrainedFloatValue = 2.0\n Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n 1 + (RF-1) \\frac{2}{\\pi}\\arctan(1.4\\frac{R_q^2}{\\delta^2})\n\n where :math:`\\delta` is skin depth, :math:`R_q` the RMS peak-to-vally height, and RF\n roughness factor.\n\nNote\n----\nThis model is based on:\n\n Y. Shlepnev, C. Nwachukwu, \"Roughness characterization for interconnect analysis\",\n 2011 IEEE International Symposium on Electromagnetic Compatibility,\n (DOI: 10.1109/ISEMC.2011.6038367), 2011.\n\n V. Dmitriev-Zdorov, B. Simonovich, I. Kochikov, \"A Causal Conductor Roughness Model\n and its Effect on Transmission Line Characteristics\", Signal Integrity Journal, 2018.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HammerstadSurfaceRoughness", + "enum": [ + "HammerstadSurfaceRoughness" + ], + "type": "string" + }, + "rq": { + "title": "RMS Peak-to-Valley Height", + "description": "RMS peak-to-valley height (Rq) of the surface roughness.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "roughness_factor": { + "title": "Roughness Factor", + "description": "Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.", + "default": 2.0, + "exclusiveMinimum": 1.0, + "type": "number" + } + }, + "required": [ + "rq" + ], + "additionalProperties": false + }, + "HuraySurfaceRoughness": { + "title": "HuraySurfaceRoughness", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HuraySurfaceRoughness", + "enum": [ + "HuraySurfaceRoughness" + ], + "type": "string" + }, + "relative_area": { + "title": "Relative Area", + "description": "Relative area of the matte base compared to a flat surface", + "default": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients for surface ratio and sphere radius", + "description": "List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.", + "units": [ + null, + "um" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "SurfaceImpedanceFitterParam": { + "title": "SurfaceImpedanceFitterParam", + "description": "Advanced parameters for fitting surface impedance of a :class:`.LossyMetalMedium`.\nInternally, the quantity to be fitted is surface impedance divided by ``-1j * \\omega``.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_num_poles : PositiveInt = 5\n Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.\ntolerance_rms : NonNegativeFloat = 0.001\n Tolerance in fitting.\nfrequency_sampling_points : PositiveInt = 20\n Number of sampling frequencies used in fitting.\nlog_sampling : bool = True\n Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "max_num_poles": { + "title": "Maximal Number Of Poles", + "description": "Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "tolerance_rms": { + "title": "Tolerance In Fitting", + "description": "Tolerance in fitting.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "frequency_sampling_points": { + "title": "Number Of Sampling Frequencies", + "description": "Number of sampling frequencies used in fitting.", + "default": 20, + "exclusiveMinimum": 0, + "type": "integer" + }, + "log_sampling": { + "title": "Frequencies Sampling In Log Scale", + "description": "Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedanceFitterParam", + "enum": [ + "SurfaceImpedanceFitterParam" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LossyMetalMedium": { + "title": "LossyMetalMedium", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Frequency range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "LossyMetalMedium", + "enum": [ + "LossyMetalMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "enum": [ + 1 + ], + "type": "integer" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "roughness": { + "title": "Surface Roughness Model", + "description": "Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.", + "discriminator": { + "propertyName": "type", + "mapping": { + "HammerstadSurfaceRoughness": "#/definitions/HammerstadSurfaceRoughness", + "HuraySurfaceRoughness": "#/definitions/HuraySurfaceRoughness" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HammerstadSurfaceRoughness" + }, + { + "$ref": "#/definitions/HuraySurfaceRoughness" + } + ] + }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "fit_param": { + "title": "Fitting Parameters For Surface Impedance", + "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", + "default": { + "attrs": {}, + "max_num_poles": 5, + "tolerance_rms": 0.001, + "frequency_sampling_points": 20, + "log_sampling": true, + "type": "SurfaceImpedanceFitterParam" + }, + "allOf": [ + { + "$ref": "#/definitions/SurfaceImpedanceFitterParam" + } + ] + } + }, + "required": [ + "frequency_range" + ], + "additionalProperties": false + }, + "PoleResidue": { + "title": "PoleResidue", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PoleResidue", + "enum": [ + "PoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + } + }, + "additionalProperties": false + }, + "Sellmeier": { + "title": "Sellmeier", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Sellmeier", + "enum": [ + "Sellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Lorentz": { + "title": "Lorentz", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Lorentz", + "enum": [ + "Lorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number", + "minimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Debye": { + "title": "Debye", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Debye", + "enum": [ + "Debye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Drude": { + "title": "Drude", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Drude", + "enum": [ + "Drude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "PECMedium": { + "title": "PECMedium", + "description": "Perfect electrical conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PECs, must import ``tidy3d.PEC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PECMedium", + "enum": [ + "PECMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AnisotropicMedium": { + "title": "AnisotropicMedium", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMedium", + "enum": [ + "AnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "FullyAnisotropicMedium": { + "title": "FullyAnisotropicMedium", + "description": "Fully anisotropic medium including all 9 components of the permittivity and conductivity\ntensors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]\n [units = None (relative permittivity)]. Relative permittivity tensor.\nconductivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n [units = S/um]. Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n Provided permittivity tensor and the symmetric part of the conductivity tensor must\n have coinciding main directions. A non-symmetric conductivity tensor can be used to model\n magneto-optic effects. Note that dispersive properties and subpixel averaging are currently not\n supported for fully anisotropic materials.\n\nNote\n----\n\n Simulations involving fully anisotropic materials are computationally more intensive, thus,\n they take longer time to complete. This increase strongly depends on the filling fraction of\n the simulation domain by fully anisotropic materials, varying approximately in the range from\n 1.5 to 5. The cost of running a simulation is adjusted correspondingly.\n\nExample\n-------\n>>> perm = [[2, 0, 0], [0, 1, 0], [0, 0, 3]]\n>>> cond = [[0.1, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> anisotropic_dielectric = FullyAnisotropicMedium(permittivity=perm, conductivity=cond)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "FullyAnisotropicMedium", + "enum": [ + "FullyAnisotropicMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity tensor.", + "default": [ + [ + 1, + 0, + 0 + ], + [ + 0, + 1, + 0 + ], + [ + 0, + 0, + 1 + ] + ], + "units": "None (relative permittivity)", + "type": "ArrayLike" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "units": "S/um", + "type": "ArrayLike" + } + }, + "additionalProperties": false + }, + "PermittivityDataset": { + "title": "PermittivityDataset", + "description": "Dataset storing the diagonal components of the permittivity tensor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\neps_xx : ScalarFieldDataArray\n Spatial distribution of the xx-component of the relative permittivity.\neps_yy : ScalarFieldDataArray\n Spatial distribution of the yy-component of the relative permittivity.\neps_zz : ScalarFieldDataArray\n Spatial distribution of the zz-component of the relative permittivity.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> sclr_fld = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = PermittivityDataset(eps_xx=sclr_fld, eps_yy=sclr_fld, eps_zz=sclr_fld)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityDataset", + "enum": [ + "PermittivityDataset" + ], + "type": "string" + }, + "eps_xx": { + "title": "DataArray", + "description": "Spatial distribution of the xx-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_yy": { + "title": "DataArray", + "description": "Spatial distribution of the yy-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_zz": { + "title": "DataArray", + "description": "Spatial distribution of the zz-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "eps_xx", + "eps_yy", + "eps_zz" + ], + "additionalProperties": false + }, + "TriangularGridDataset": { + "title": "TriangularGridDataset", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangularGridDataset", + "enum": [ + "TriangularGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "normal_axis": { + "title": "Grid Axis", + "description": "Orientation of the grid.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "normal_pos": { + "title": "Position", + "description": "Coordinate of the grid along the normal direction.", + "type": "number" + } + }, + "required": [ + "points", + "values", + "cells", + "normal_axis", + "normal_pos" + ], + "additionalProperties": false + }, + "TetrahedralGridDataset": { + "title": "TetrahedralGridDataset", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TetrahedralGridDataset", + "enum": [ + "TetrahedralGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "points", + "values", + "cells" + ], + "additionalProperties": false + }, + "CustomMedium": { + "title": "CustomMedium", + "description": ":class:`.Medium` with user-supplied permittivity distribution.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\neps_dataset : Optional[PermittivityDataset] = None\n [To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.\npermittivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = None (relative permittivity)]. Spatial profile of relative permittivity.\nconductivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = S/um]. Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> dielectric = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> eps = dielectric.eps_model(200e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomMedium", + "enum": [ + "CustomMedium" + ], + "type": "string" + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + }, + "eps_dataset": { + "title": "Permittivity Dataset", + "description": "[To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.", + "allOf": [ + { + "$ref": "#/definitions/PermittivityDataset" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Spatial profile of relative permittivity.", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "units": "S/um", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + }, + "additionalProperties": false + }, + "CustomPoleResidue": { + "title": "CustomPoleResidue", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomPoleResidue", + "enum": [ + "CustomPoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf" + ], + "additionalProperties": false + }, + "CustomSellmeier": { + "title": "CustomSellmeier", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomSellmeier", + "enum": [ + "CustomSellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "CustomLorentz": { + "title": "CustomLorentz", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomLorentz", + "enum": [ + "CustomLorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDebye": { + "title": "CustomDebye", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDebye", + "enum": [ + "CustomDebye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDrude": { + "title": "CustomDrude", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDrude", + "enum": [ + "CustomDrude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomAnisotropicMedium": { + "title": "CustomAnisotropicMedium", + "description": "Diagonally anisotropic medium with spatially varying permittivity in each component.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\ninterp_method : Optional[Literal['nearest', 'linear']] = None\n When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.\nsubpixel : Optional[bool] = None\n This field is ignored. Please set ``subpixel`` in each component\n\nNote\n----\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> x = np.linspace(-1, 1, Nx)\n>>> y = np.linspace(-1, 1, Ny)\n>>> z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=x, y=y, z=z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> medium_xx = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> medium_yy = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> d_epsilon = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> medium_zz = CustomLorentz(eps_inf=permittivity, coeffs=[(d_epsilon,f,delta),])\n>>> anisotropic_dielectric = CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomAnisotropicMedium", + "enum": [ + "CustomAnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This field is ignored. Please set ``subpixel`` in each component", + "type": "boolean" + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "LinearHeatPerturbation": { + "title": "LinearHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a linear function of\ntemperature.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n [units = K]. Temperature range in which perturbation model is valid.\ntemperature_ref : NonNegativeFloat\n [units = K]. Temperature at which perturbation is zero.\ncoeff : Union[float, tidycomplex, ComplexNumber]\n [units = 1/K]. Sensitivity (derivative) of perturbation with respect to temperature.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{coeff} \\times (T - \\text{temperature\\_ref}),\n\n where ``coeff`` is the parameter's sensitivity (thermo-optic coefficient) to temperature and\n ``temperature_ref`` is the reference temperature point. A temperature range in which such\n a model is deemed accurate may be provided as a field ``temperature_range``\n (default: ``[0, inf]``). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.0001,\n... temperature_range=[200, 500],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearHeatPerturbation", + "enum": [ + "LinearHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "temperature_ref": { + "title": "Reference temperature", + "description": "Temperature at which perturbation is zero.", + "units": "K", + "minimum": 0, + "type": "number" + }, + "coeff": { + "title": "Thermo-optic Coefficient", + "description": "Sensitivity (derivative) of perturbation with respect to temperature.", + "units": "1/K", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "required": [ + "temperature_ref", + "coeff" + ], + "additionalProperties": false + }, + "CustomHeatPerturbation": { + "title": "CustomHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a custom function of\ntemperature defined as an array of perturbation values at sample temperature points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n [units = K]. Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.\nperturbation_values : HeatDataArray\n Sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\n Notes\n -----\n\n The linear\n interpolation is used to calculate perturbation values between sample temperature points. For\n temperature values outside of the provided sample region the perturbation value is extrapolated\n as a constant.\n The temperature range, ``temperature_range``, in which the perturbation model is assumed to be\n accurate is calculated automatically as the minimal and maximal sample temperature points.\n Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> from tidy3d import HeatDataArray\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomHeatPerturbation", + "enum": [ + "CustomHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.", + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "Sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "LinearChargePerturbation": { + "title": "LinearChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a linear function of\nelectron and hole densities:\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of electrons densities in which perturbation model is valid.\nhole_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of holes densities in which perturbation model is valid.\nelectron_ref : NonNegativeFloat\n [units = 1/cm^3]. Electron density value at which there is no perturbation due to electrons's presence.\nhole_ref : NonNegativeFloat\n [units = 1/cm^3]. Hole density value at which there is no perturbation due to holes' presence.\nelectron_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to electron density.\nhole_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to hole density.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{electron\\_coeff} \\times (N_e - \\text{electron\\_ref})\n + \\text{hole\\_coeff} \\times (N_h - \\text{hole\\_ref}),\n\n where ``electron_coeff`` and ``hole_coeff`` are the parameter's sensitivities to electron and\n hole densities, while ``electron_ref`` and ``hole_ref`` are reference electron and hole density\n values. Ranges of electron and hole densities in which such\n a model is deemed accurate may be provided as fields ``electron_range`` and ``hole_range``\n (default: ``[0, inf]`` each). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``electron_range`` x ``hole_range`` due to\n perturbations and raise a warning if this check fails. A warning is also issued if\n the perturbation model is evaluated outside of ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearChargePerturbation", + "enum": [ + "LinearChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "electron_ref": { + "title": "Reference Electron Density", + "description": "Electron density value at which there is no perturbation due to electrons's presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "hole_ref": { + "title": "Reference Hole Density", + "description": "Hole density value at which there is no perturbation due to holes' presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "electron_coeff": { + "title": "Sensitivity to Electron Density", + "description": "Sensitivity (derivative) of perturbation with respect to electron density.", + "units": "cm^3", + "type": "number" + }, + "hole_coeff": { + "title": "Sensitivity to Hole Density", + "description": "Sensitivity (derivative) of perturbation with respect to hole density.", + "units": "cm^3", + "type": "number" + } + }, + "required": [ + "electron_ref", + "hole_ref", + "electron_coeff", + "hole_coeff" + ], + "additionalProperties": false + }, + "CustomChargePerturbation": { + "title": "CustomChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a custom function of\nelectron and hole densities defined as a two-dimensional array of perturbation values at sample\nelectron and hole density points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nhole_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nperturbation_values : ChargeDataArray\n 2D array (vs electron and hole densities) of sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\nNotes\n-----\n\n The linear interpolation is used to calculate perturbation\n values between sample points. For electron and hole density values outside of the provided\n sample region the perturbation value is extrapolated as a constant.\n The electron and hole density ranges, ``electron_range`` and ``hole_range``, in which\n the perturbation model is assumed to be accurate is calculated automatically as the minimal and\n maximal density values provided in ``perturbation_values``. Wherever is applied, Tidy3D will\n check that the parameter's value does not go out of its physical bounds within\n ``electron_range`` x ``hole_range`` due to perturbations and raise a warning if this check\n fails. A warning is also issued if the perturbation model is evaluated outside of\n ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> from tidy3d import ChargeDataArray\n>>> perturbation_data = ChargeDataArray(\n... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],\n... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),\n... )\n>>> charge_perturb = CustomChargePerturbation(\n... perturbation_values=perturbation_data,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomChargePerturbation", + "enum": [ + "CustomChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "2D array (vs electron and hole densities) of sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "ParameterPerturbation": { + "title": "ParameterPerturbation", + "description": "Stores information about parameter perturbations due to different physical effect. If both\nheat and charge perturbation models are included their effects are superimposed.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nheat : Union[LinearHeatPerturbation, CustomHeatPerturbation] = None\n Heat perturbation to apply.\ncharge : Union[LinearChargePerturbation, CustomChargePerturbation] = None\n Charge perturbation to apply.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, CustomHeatPerturbation, HeatDataArray\n>>>\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )\n>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "heat": { + "title": "Heat Perturbation", + "description": "Heat perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearHeatPerturbation": "#/definitions/LinearHeatPerturbation", + "CustomHeatPerturbation": "#/definitions/CustomHeatPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearHeatPerturbation" + }, + { + "$ref": "#/definitions/CustomHeatPerturbation" + } + ] + }, + "charge": { + "title": "Charge Perturbation", + "description": "Charge perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearChargePerturbation": "#/definitions/LinearChargePerturbation", + "CustomChargePerturbation": "#/definitions/CustomChargePerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearChargePerturbation" + }, + { + "$ref": "#/definitions/CustomChargePerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "ParameterPerturbation", + "enum": [ + "ParameterPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityPerturbation": { + "title": "PermittivityPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\npermittivity and conductivity.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_eps : Optional[ParameterPerturbation] = None\n Perturbation model for permittivity.\ndelta_sigma : Optional[ParameterPerturbation] = None\n Perturbation model for conductivity.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, PermittivityPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> delta_eps = ParameterPerturbation(heat=heat_perturb)\n>>> delta_sigma = ParameterPerturbation(charge=charge_perturb)\n>>> permittivity_pb = PermittivityPerturbation(delta_eps=delta_eps, delta_sigma=delta_sigma)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_eps": { + "title": "Permittivity Perturbation", + "description": "Perturbation model for permittivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_sigma": { + "title": "Conductivity Perturbation", + "description": "Perturbation model for conductivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PermittivityPerturbation", + "enum": [ + "PermittivityPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IndexPerturbation": { + "title": "IndexPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\nrefractive index, n and k.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_n : Optional[ParameterPerturbation] = None\n Perturbation of the real part of refractive index.\ndelta_k : Optional[ParameterPerturbation] = None\n Perturbation of the imaginary part of refractive index.\nfreq : NonNegativeFloat\n [units = Hz]. Frequency to evaluate permittivity at (Hz).\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, IndexPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> dn_pb = ParameterPerturbation(heat=heat_perturb)\n>>> dk_pb = ParameterPerturbation(charge=charge_perturb)\n>>> index_pb = IndexPerturbation(delta_n=dn_pb, delta_k=dk_pb, freq=C_0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_n": { + "title": "Refractive Index Perturbation", + "description": "Perturbation of the real part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_k": { + "title": "Exctinction Coefficient Perturbation", + "description": "Perturbation of the imaginary part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "freq": { + "title": "Frequency", + "description": "Frequency to evaluate permittivity at (Hz).", + "units": "Hz", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "IndexPerturbation", + "enum": [ + "IndexPerturbation" + ], + "type": "string" + } + }, + "required": [ + "freq" + ], + "additionalProperties": false + }, + "PerturbationMedium": { + "title": "PerturbationMedium", + "description": "Dispersionless medium with perturbations. Perturbation model can be defined either directly\nthrough providing ``permittivity_perturbation`` and ``conductivity_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\npermittivity_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. List of heat and/or charge perturbations to permittivity.\nconductivity_perturbation : Optional[ParameterPerturbation] = None\n [units = S/um]. List of heat and/or charge perturbations to permittivity.\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> dielectric = PerturbationMedium(\n... permittivity=4.0,\n... permittivity_perturbation=ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... ),\n... name='my_medium',\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationMedium", + "enum": [ + "PerturbationMedium" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "permittivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "conductivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "S/um", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + }, + "additionalProperties": false + }, + "PerturbationPoleResidue": { + "title": "PerturbationPoleResidue", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationPoleResidue", + "enum": [ + "PerturbationPoleResidue" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + }, + "eps_inf_perturbation": { + "title": "Perturbation of Epsilon at Infinity", + "description": "Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "poles_perturbation": { + "title": "Perturbations of Poles", + "description": "Perturbations to poles of the model.", + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "$ref": "#/definitions/ParameterPerturbation" + }, + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + } + }, + "additionalProperties": false + }, + "Box": { + "title": "Box", + "description": "Rectangular prism.\n Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\n\nExample\n-------\n>>> b = Box(center=(1,2,3), size=(2,2,2))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Box", + "enum": [ + "Box" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "Sphere": { + "title": "Sphere", + "description": "Spherical geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nradius : NonNegativeFloat\n [units = um]. Radius of geometry.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\n\nExample\n-------\n>>> b = Sphere(center=(1,2,3), radius=2)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Sphere", + "enum": [ + "Sphere" + ], + "type": "string" + }, + "radius": { + "title": "Radius", + "description": "Radius of geometry.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "radius" + ], + "additionalProperties": false + }, + "Cylinder": { + "title": "Cylinder", + "description": "Cylindrical geometry with optional sidewall angle along axis\ndirection. When ``sidewall_angle`` is nonzero, the shape is a\nconical frustum or a cone.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> c = Cylinder(center=(1,2,3), radius=2, length=5, axis=2)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../../notebooks/THzDemultiplexerFilter.html>`_\n* `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Cylinder", + "enum": [ + "Cylinder" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([(0,0), (1,0), (1,1)])\n>>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolySlab", + "enum": [ + "PolySlab" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])\n>>> faces = np.array([[1, 2, 3], [0, 3, 2], [0, 1, 3], [0, 2, 1]])\n>>> stl_geom = TriangleMesh.from_vertices_faces(vertices, faces)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangleMesh", + "enum": [ + "TriangleMesh" + ], + "type": "string" + }, + "mesh_dataset": { + "title": "Surface mesh data", + "description": "Surface mesh data.", + "allOf": [ + { + "$ref": "#/definitions/TriangleMeshDataset" + } + ] + } + }, + "required": [ + "mesh_dataset" + ], + "additionalProperties": false + }, + "GeometryGroup": { + "title": "GeometryGroup", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GeometryGroup", + "enum": [ + "GeometryGroup" + ], + "type": "string" + }, + "geometries": { + "title": "Geometries", + "description": "Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + } + }, + "required": [ + "geometries" + ], + "additionalProperties": false + }, + "ClipOperation": { + "title": "ClipOperation", + "description": "Class representing the result of a set operation between geometries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\noperation : Literal['union', 'intersection', 'difference', 'symmetric_difference']\n Operation to be performed between geometries.\ngeometry_a : ForwardRef('annotate_type(GeometryType)')\n First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.\ngeometry_b : ForwardRef('annotate_type(GeometryType)')\n Second operand for the set operation. It can also be any geometry type.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ClipOperation", + "enum": [ + "ClipOperation" + ], + "type": "string" + }, + "operation": { + "title": "Operation Type", + "description": "Operation to be performed between geometries.", + "enum": [ + "union", + "intersection", + "difference", + "symmetric_difference" + ], + "type": "string" + }, + "geometry_a": { + "title": "Geometry A", + "description": "First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "geometry_b": { + "title": "Geometry B", + "description": "Second operand for the set operation. It can also be any geometry type.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + }, + "required": [ + "operation", + "geometry_a", + "geometry_b" + ], + "additionalProperties": false + }, + "Transformed": { + "title": "Transformed", + "description": "Class representing a transformed geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : ForwardRef('annotate_type(GeometryType)')\n Base geometry to be transformed.\ntransform : ArrayLike[dtype=float, ndim=2, shape=(4, 4)] = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]\n Transform matrix applied to the base geometry.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Transformed", + "enum": [ + "Transformed" + ], + "type": "string" + }, + "geometry": { + "title": "Geometry", + "description": "Base geometry to be transformed.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "transform": { + "title": "Transform", + "description": "Transform matrix applied to the base geometry.", + "default": [ + [ + 1.0, + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "type": "ArrayLike" + } + }, + "required": [ + "geometry" + ], + "additionalProperties": false + }, + "Medium2D": { + "title": "Medium2D", + "description": "2D diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nss : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.\ntt : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> medium2d = Medium2D(ss=drude_medium, tt=drude_medium)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium2D", + "enum": [ + "Medium2D" + ], + "type": "string" + }, + "ss": { + "title": "SS Component", + "description": "Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + }, + "tt": { + "title": "TT Component", + "description": "Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + } + }, + "required": [ + "ss", + "tt" + ], + "additionalProperties": false + }, + "AnisotropicMediumFromMedium2D": { + "title": "AnisotropicMediumFromMedium2D", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMediumFromMedium2D", + "enum": [ + "AnisotropicMediumFromMedium2D" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "ChargeConductorMedium": { + "title": "ChargeConductorMedium", + "description": "Conductor medium for conduction simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : PositiveFloat\n [units = S/um]. Electric conductivity of material in units of S/um.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeConductorMedium(conductivity=3)\n\nNote\n----\n A relative permittivity will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeConductorMedium", + "enum": [ + "ChargeConductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "conductivity": { + "title": "Electric conductivity", + "description": "Electric conductivity of material in units of S/um.", + "units": "S/um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "ChargeInsulatorMedium": { + "title": "ChargeInsulatorMedium", + "description": "Insulating medium. Conduction simulations will not solve for electric\npotential in a structure that has a medium with this 'charge'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeInsulatorMedium()\n>>> solid2 = td.ChargeInsulatorMedium(permittivity=1.1)\n\nNote\n----\n A relative permittivity :math:`\\varepsilon` will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeInsulatorMedium", + "enum": [ + "ChargeInsulatorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + } + }, + "additionalProperties": false + }, + "CaugheyThomasMobility": { + "title": "CaugheyThomasMobility", + "description": "The Caughey-Thomas temperature-dependent carrier mobility model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu_min : PositiveFloat\n Minimum electron mobility at reference temperature (300K) in cm^2/V-s. \nmu : PositiveFloat\n Reference mobility at reference temperature (300K) in cm^2/V-s\nexp_2 : float\n exp_N : PositiveFloat\n Exponent for doping dependence of mobility at reference temperature (300K).\nref_N : PositiveFloat\n Reference doping at reference temperature (300K) in #/cm^3.\nexp_1 : float\n Exponent of thermal dependence of minimum mobility.\nexp_3 : float\n Exponent of thermal dependence of reference doping.\nexp_4 : float\n Exponent of thermal dependence of the doping exponent effect.\n\nNotes\n-----\n The general form of the Caughey-Thomas mobility model [1]_ is of the form:\n\n .. math::\n\n \\mu_0 = \\frac{\\mu_{max} - \\mu_{min}}{1 + \\left(N/N_{ref}\\right)^z} + \\mu_{min}\n\nwhere :math:`\\mu_0` represents the low-field mobility and :math:`N` is the total doping (acceptors + donors).\n:math:`\\mu_{max}`, :math:`\\mu_{min}`, :math:`z`, and :math:`N_{ref}` are temperature dependent,\nthe dependence being of the form\n\n.. math::\n\n \\phi = \\phi_{ref} \\left( \\frac{T}{T_{ref}}\\right)^\\alpha\n\nand :math:`T_{ref}` is taken to be 300K.\n\nThe complete form (with temperature effects) for the low-field mobility can be written as\n\n.. math::\n\n \\mu_0 = \\frac{\\mu_{max}(\\frac{T}{T_{ref}})^{\\alpha_2} - \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}}{1 + \\left(N/N_{ref}(\\frac{T}{T_{ref}})^{\\alpha_3}\\right)^{\\alpha_N(\\frac{T}{T_{ref}})^{\\alpha_4}}} + \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}\n\nThe following table maps the symbols used in the equations above with the names used in the code:\n\n.. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`\\mu_{min}`\n - ``mu_min``\n - Minimum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\mu_{max}`\n - ``mu_n``\n - Maximum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\alpha_1`\n - ``exp_1``\n - Exponent for temperature dependence of the minimum mobility coefficient\n * - :math:`\\alpha_2`\n - ``exp_2``\n - Exponent for temperature dependence of the maximum mobility coefficient\n * - :math:`\\alpha_N`\n - ``exp_N``\n - Exponent for doping dependence.\n * - :math:`\\alpha_4`\n - ``exp_4``\n - Exponent for the temperature dependence of the exponent :math:`\\alpha_N`\n * - :math:`N_{ref}`\n - ``ref_N``,\n - Reference doping parameter\n\n\n.. [1] M. Caughey and R.E. Thomas. Carrier mobilities in silicon empirically related to doping\n and field. Proceedings of the IEEE, 55(12):2192\u20132193, December 1967\n\nExample\n-------\n >>> import tidy3d as td\n >>> mobility_Si_n = td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n >>> mobility_Si_p = td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n\n\nWarning\n-------\nThere are some current limitations of this model:\n\n- High electric field effects not yet supported.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu_min": { + "title": "$\\mu_{min}$ Minimum electron mobility", + "description": "Minimum electron mobility at reference temperature (300K) in cm^2/V-s. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "mu": { + "title": "Reference mobility", + "description": "Reference mobility at reference temperature (300K) in cm^2/V-s", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_2": { + "title": "Exponent for temperature dependent behavior of reference mobility", + "type": "number" + }, + "exp_N": { + "title": "Exponent for doping dependence of mobility.", + "description": "Exponent for doping dependence of mobility at reference temperature (300K).", + "exclusiveMinimum": 0, + "type": "number" + }, + "ref_N": { + "title": "Reference doping", + "description": "Reference doping at reference temperature (300K) in #/cm^3.", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_1": { + "title": "Exponent of thermal dependence of minimum mobility.", + "description": "Exponent of thermal dependence of minimum mobility.", + "type": "number" + }, + "exp_3": { + "title": "Exponent of thermal dependence of reference doping.", + "description": "Exponent of thermal dependence of reference doping.", + "type": "number" + }, + "exp_4": { + "title": "Exponent of thermal dependence of the doping exponent effect.", + "description": "Exponent of thermal dependence of the doping exponent effect.", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CaugheyThomasMobility", + "enum": [ + "CaugheyThomasMobility" + ], + "type": "string" + } + }, + "required": [ + "mu_min", + "mu", + "exp_2", + "exp_N", + "ref_N", + "exp_1", + "exp_3", + "exp_4" + ], + "additionalProperties": false + }, + "ConstantMobilityModel": { + "title": "ConstantMobilityModel", + "description": "Constant mobility model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu : NonNegativeFloat\n [units = cm\u00b2/V-s]. Mobility\n\nExample\n-------\n>>> import tidy3d as td\n>>> mobility_model = td.ConstantMobilityModel(mu=1500)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu": { + "title": "Mobility", + "description": "Mobility", + "units": "cm\u00b2/V-s", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ConstantMobilityModel", + "enum": [ + "ConstantMobilityModel" + ], + "type": "string" + } + }, + "required": [ + "mu" + ], + "additionalProperties": false + }, + "AugerRecombination": { + "title": "AugerRecombination", + "description": "Parameters for the Auger recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nc_n : PositiveFloat\n Constant for electrons in cm^6/s\nc_p : PositiveFloat\n Constant for holes in cm^6/s\n\nNotes\n-----\n\n The Auger recombination rate ``R_A`` is primarily defined by the electrons and holes Auger recombination\n coefficients, :math:`C_n` and :math:`C_p`, respectively.\n\n .. math::\n\n R_A = \\left( C_n n + C_p p \\right) \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32,\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "c_n": { + "title": "Constant for electrons", + "description": "Constant for electrons in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "c_p": { + "title": "Constant for holes", + "description": "Constant for holes in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AugerRecombination", + "enum": [ + "AugerRecombination" + ], + "type": "string" + } + }, + "required": [ + "c_n", + "c_p" + ], + "additionalProperties": false + }, + "RadiativeRecombination": { + "title": "RadiativeRecombination", + "description": "Defines the parameters for the radiative recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr_const : float\n Radiation constant in cm^3/s\n\nNotes\n-----\n\n This is a direct recombination model primarily defined by a radiative recombination coefficient :math:`R_{\\text{rad}}`.\n\n .. math::\n\n R_{\\text{rad}} = C \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r_const": { + "title": "Radiation constant in cm^3/s", + "description": "Radiation constant in cm^3/s", + "type": "number" + }, + "type": { + "title": "Type", + "default": "RadiativeRecombination", + "enum": [ + "RadiativeRecombination" + ], + "type": "string" + } + }, + "required": [ + "r_const" + ], + "additionalProperties": false + }, + "FossumCarrierLifetime": { + "title": "FossumCarrierLifetime", + "description": "Parameters for the Fossum carrier lifetime model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_300 : PositiveFloat\n [units = sec]. Carrier lifetime at 300K\nalpha_T : float\n Exponent for thermal dependence\nN0 : PositiveFloat\n [units = 1/cm^3]. Reference concentration\nA : float\n Constant A\nB : float\n Constant B\nC : float\n Constant C\nalpha : float\n Exponent constant\n\nNotes\n-----\n\n This model expresses the carrier lifetime as a function of the temperature and doping concentration.\n\n .. math::\n\n \\tau = \\frac{\\tau_{300} \\left( T/300 \\right)^\\alpha_T}{A + B (N/N_0) + C (N/N_0)^\\alpha}\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.FossumCarrierLifetime(\n ... tau_300=3.3e-6,\n ... alpha_T=-0.5,\n ... N0=7.1e15,\n ... A=1,\n ... B=0,\n ... C=1,\n ... alpha=1\n ... )\n\nReferences\n----------\n\n Fossum, J. G., and D. S. Lee. \"A physical model for the dependence of carrier lifetime on doping density in nondegenerate silicon.\" Solid-State Electronics 25.8 (1982): 741-747.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_300": { + "title": "Tau at 300K", + "description": "Carrier lifetime at 300K", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "alpha_T": { + "title": "Exponent for thermal dependence", + "description": "Exponent for thermal dependence", + "type": "number" + }, + "N0": { + "title": "Reference concentration", + "description": "Reference concentration", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "A": { + "title": "Constant A", + "description": "Constant A", + "type": "number" + }, + "B": { + "title": "Constant B", + "description": "Constant B", + "type": "number" + }, + "C": { + "title": "Constant C", + "description": "Constant C", + "type": "number" + }, + "alpha": { + "title": "Exponent constant", + "description": "Exponent constant", + "type": "number" + }, + "type": { + "title": "Type", + "default": "FossumCarrierLifetime", + "enum": [ + "FossumCarrierLifetime" + ], + "type": "string" + } + }, + "required": [ + "tau_300", + "alpha_T", + "N0", + "A", + "B", + "C", + "alpha" + ], + "additionalProperties": false + }, + "ShockleyReedHallRecombination": { + "title": "ShockleyReedHallRecombination", + "description": "Defines the parameters for the Shockley-Reed-Hall (SRH) recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_n : Union[PositiveFloat, FossumCarrierLifetime]\n Electron lifetime\ntau_p : Union[PositiveFloat, FossumCarrierLifetime]\n [units = sec]. Hole lifetime\n\nNotes\n-----\n\n The recombination rate parameter from this model is defined from [1]_ as follows:\n\n .. math::\n\n R_{SRH} = \\frac{n p - n_0 p_0}{\\tau_p \\left(n + \\sqrt{n_0 p_0}\\right) + \\tau_n \\left(p + \\sqrt{n_0 p_0}\\right)}.\n\n Note that the electron and holes densities are defined within the :class:`SemiconductorMedium`. The electron\n lifetime :math:`\\tau_n` and hole lifetimes :math:`\\tau_p` need to be defined.\n\n\n .. [1] Schenk. A model for the field and temperature dependence of shockley-read-hall\n lifetimes in silicon. Solid-State Electronics, 35:1585\u20131596, 1992.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6,\n ... )\n\nNote\n----\nImportant considerations when using this model:\n\n- Currently, lifetimes are considered constant (not dependent on temperature or doping).\n- This model represents mid-gap traps Shockley-Reed-Hall recombination.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_n": { + "title": "Electron lifetime", + "description": "Electron lifetime", + "union": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "tau_p": { + "title": "Hole lifetime", + "description": "Hole lifetime", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "type": { + "title": "Type", + "default": "ShockleyReedHallRecombination", + "enum": [ + "ShockleyReedHallRecombination" + ], + "type": "string" + } + }, + "required": [ + "tau_n", + "tau_p" + ], + "additionalProperties": false + }, + "SlotboomBandGapNarrowing": { + "title": "SlotboomBandGapNarrowing", + "description": "Parameters for the Slotboom model for band-gap narrowing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nv1 : PositiveFloat\n [units = V]. $V_{1,bgn}$ parameter\nn2 : PositiveFloat\n [units = 1/cm^3]. $N_{2,bgn}$ parameter\nc2 : float\n $C_{2,bgn}$ parameter\nmin_N : NonNegativeFloat\n [units = 1/cm^3]. Bandgap narrowing is applied at location where total doping is higher than 'min_N'.\n\nNotes\n------\n The Slotboom band-gap narrowing :math:`\\Delta E_G` model is discussed in [1]_ as follows:\n\n .. math::\n\n \\Delta E_G = V_{1,bgn} \\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right)\n + \\sqrt{\\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right) \\right)^2 + C_{2,bgn}} \\right)\n \\quad \\text{if} \\quad N_{tot} \\geq 10^{15} \\text{cm}^{-3},\n\n \\Delta E_G = 0 \\quad \\text{if} \\quad N_{tot} < 10^{15} \\text{cm}^{-3}.\n\n Note that :math:`N_{tot}` is the total doping as defined within a :class:`SemiconductorMedium`.\n\n Example\n -------\n >>> import tidy3d as td\n >>> default_Si = td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... )\n\n .. [1] 'UNIFIED APPARENT BANDGAP NARROWING IN n- AND p-TYPE SILICON' Solid-State Electronics Vol. 35, No. 2, pp. 125-129, 1992", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "v1": { + "title": "$V_{1,bgn}$ parameter", + "description": "$V_{1,bgn}$ parameter", + "units": "V", + "exclusiveMinimum": 0, + "type": "number" + }, + "n2": { + "title": "$N_{2,bgn}$ parameter", + "description": "$N_{2,bgn}$ parameter", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "c2": { + "title": "$C_{2,bgn}$ parameter", + "description": "$C_{2,bgn}$ parameter", + "type": "number" + }, + "min_N": { + "title": "Minimum total doping", + "description": "Bandgap narrowing is applied at location where total doping is higher than 'min_N'.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "SlotboomBandGapNarrowing", + "enum": [ + "SlotboomBandGapNarrowing" + ], + "type": "string" + } + }, + "required": [ + "v1", + "n2", + "c2", + "min_N" + ], + "additionalProperties": false + }, + "ConstantDoping": { + "title": "ConstantDoping", + "description": "Sets constant doping :math:`N` in the specified box with a :parameter`size` and :parameter:`concentration`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nconcentration : NonNegativeFloat = 0\n [units = 1/cm^3]. Doping concentration density in #/cm^3.\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> constant_box1 = td.ConstantDoping(center=(0, 0, 0), size=(2, 2, 2), concentration=1e18)\n>>> constant_box2 = td.ConstantDoping.from_bounds(rmin=box_coords[0], rmax=box_coords[1], concentration=1e18)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConstantDoping", + "enum": [ + "ConstantDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "concentration": { + "title": "Doping concentration density.", + "description": "Doping concentration density in #/cm^3.", + "default": 0, + "units": "1/cm^3", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "GaussianDoping": { + "title": "GaussianDoping", + "description": "Sets a gaussian doping in the specified box.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nref_con : PositiveFloat\n Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.\nconcentration : PositiveFloat\n The concentration at the center of the box.\nwidth : PositiveFloat\n Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. \nsource : str = xmin\n Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nNotes\n-----\nThe Gaussian doping concentration :math:`N` is defined in the following manner:\n\n- :math:`N=N_{\\text{max}}` at locations more than :math:``width`` um away from the sides of the box.\n- :math:`N=N_{\\text{ref}}` at location on the box sides.\n- a Gaussian variation between :math:`N_{\\text{max}}` and :math:`N_{\\text{ref}}` at locations less than ``width``\num away from the sides.\n\nBy definition, all sides of the box will have concentration :math:`N_{\\text{ref}}` (except the side specified\nas source) and the center of the box (``width`` away from the box sides) will have a concentration\n:math:`N_{\\text{max}}`.\n\n.. math::\n\n N = \\{N_{\\text{max}}\\} \\exp \\left[\n - \\ln \\left( \\frac{\\{N_{\\text{max}}\\}}{\\{N_{\\text{ref}}\\}} \\right)\n \\left( \\frac{(x|y|z) - \\{(x|y|z)_{\\text{box}}\\}}{\\text{width}} \\right)^2\n \\right]\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> gaussian_box1 = td.GaussianDoping(\n... center=(0, 0, 0),\n... size=(2, 2, 2),\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )\n>>> gaussian_box2 = td.GaussianDoping.from_bounds(\n... rmin=box_coords[0],\n... rmax=box_coords[1],\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GaussianDoping", + "enum": [ + "GaussianDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "ref_con": { + "title": "Reference concentration.", + "description": "Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concentration": { + "title": "Concentration", + "description": "The concentration at the center of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "width": { + "title": "Width of the gaussian.", + "description": "Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "source": { + "title": "Source face", + "description": "Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']", + "default": "xmin", + "type": "string" + } + }, + "required": [ + "size", + "ref_con", + "concentration", + "width" + ], + "additionalProperties": false + }, + "SemiconductorMedium": { + "title": "SemiconductorMedium", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "SemiconductorMedium", + "enum": [ + "SemiconductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "N_c": { + "title": "Effective density of electron states", + "description": "$N_c$ Effective density of states in the conduction band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "N_v": { + "title": "Effective density of hole states", + "description": "$N_v$ Effective density of states in the valence band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "E_g": { + "title": "Band-gap energy", + "description": "Band-gap energy", + "units": "eV", + "exclusiveMinimum": 0, + "type": "number" + }, + "mobility_n": { + "title": "Mobility model for electrons", + "description": "Mobility model for electrons", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "mobility_p": { + "title": "Mobility model for holes", + "description": "Mobility model for holes", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "R": { + "title": "Generation-Recombination models", + "description": "Array containing the R models to be applied to the material.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/AugerRecombination" + }, + { + "$ref": "#/definitions/RadiativeRecombination" + }, + { + "$ref": "#/definitions/ShockleyReedHallRecombination" + } + ] + } + }, + "delta_E_g": { + "title": "$\\Delta E_g$ Bandgap narrowing model.", + "description": "Bandgap narrowing model.", + "allOf": [ + { + "$ref": "#/definitions/SlotboomBandGapNarrowing" + } + ] + }, + "N_a": { + "title": "Doping: Acceptor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + }, + "N_d": { + "title": "Doping: Donor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + } + }, + "required": [ + "N_c", + "N_v", + "E_g", + "mobility_n", + "mobility_p" + ], + "additionalProperties": false + }, + "MultiPhysicsMedium": { + "title": "MultiPhysicsMedium", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Medium name", + "type": "string" + }, + "optical": { + "title": "Optical properties", + "description": "Specifies optical properties.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "heat": { + "title": "Heat properties", + "description": "Specifies properties for Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "charge": { + "title": "Charge properties", + "description": "Specifies properties for Charge simulations.", + "anyOf": [ + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "MultiPhysicsMedium", + "enum": [ + "MultiPhysicsMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Structure": { + "title": "Structure", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, + "type": { + "title": "Type", + "default": "Structure", + "enum": [ + "Structure" + ], + "type": "string" + }, + "medium": { + "title": "Medium", + "description": "Defines the electromagnetic properties of the structure's medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + } + }, + "required": [ + "geometry", + "medium" + ], + "additionalProperties": false + }, + "Periodic": { + "title": "Periodic", + "description": "Periodic boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Periodic", + "enum": [ + "Periodic" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECBoundary": { + "title": "PECBoundary", + "description": "Perfect electric conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PECBoundary", + "enum": [ + "PECBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCBoundary": { + "title": "PMCBoundary", + "description": "Perfect magnetic conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PMCBoundary", + "enum": [ + "PMCBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMLParams": { + "title": "PMLParams", + "description": "Specifies full set of parameters needed for complex, frequency-shifted PML.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\nkappa_order : NonNegativeInt = 3\n Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).\nkappa_min : NonNegativeFloat = 0.0\n \nkappa_max : NonNegativeFloat = 1.5\n \nalpha_order : NonNegativeInt = 3\n Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).\nalpha_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the PML alpha.\nalpha_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the PML alpha.\n\nExample\n-------\n>>> params = PMLParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5, kappa_min=0.0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "PMLParams", + "enum": [ + "PMLParams" + ], + "type": "string" + }, + "kappa_order": { + "title": "Kappa Order", + "description": "Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "kappa_min": { + "title": "Kappa Minimum", + "default": 0.0, + "minimum": 0, + "type": "number" + }, + "kappa_max": { + "title": "Kappa Maximum", + "default": 1.5, + "minimum": 0, + "type": "number" + }, + "alpha_order": { + "title": "Alpha Order", + "description": "Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "alpha_min": { + "title": "Alpha Minimum", + "description": "Minimum value of the PML alpha.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "alpha_max": { + "title": "Alpha Maximum", + "description": "Maximum value of the PML alpha.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "PML": { + "title": "PML", + "description": "Specifies a standard PML along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 12\n Number of layers of standard PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.5, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=3.0, alpha_order=1, alpha_min=0.0, alpha_max=0.0)\n Parameters of the complex frequency-shifted absorption poles.\n\nNotes\n------\n\n **1D Model Illustration**\n\n Consider a transformed wave equation in the :math:`x` dimension below _`[1]`:\n\n .. math::\n\n \\left( \\left( \\frac{1}{s(x)} \\frac{\\delta}{\\delta x} \\right)^2 - \\frac{1}{c^2} \\frac{\\delta^2}{\\delta t^2} \\right) E = 0\n\n where the wave stretch factor :math:`s(x)` depends on the PML boundary position in the :math:`x` dimension.\n\n .. TODO what is x at 0?\n\n .. math::\n\n s(x) = \\left \\{\n \\begin{array}{lr}\n 1, & \\text{for } x < 0 \\\\\n 1 - \\frac{\\sigma}{i \\omega \\epsilon_0}, & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n The wave equation can be solved and plotted accordingly as a function of the :math:`x` dimension.\n\n .. math::\n\n E(x) = \\left \\{\n \\begin{array}{lr}\n e^{i(kx - \\omega t)}, & \\text{for } x < 0 \\\\\n e^{i(kx - \\omega t)} \\times e^{-\\frac{\\sigma x}{c \\epsilon_0}} & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n Hence, we see how this PML stretch factor induces frequency-independent exponential attentation and no\n reflection after the boundary at :math:`x=0`.\n\n .. image:: ../../_static/img/pml_boundary.png\n\n .. TODO make this image better\n\n **Usage Caveats**\n\n A perfectly matched layer (PML) is the most commonly used boundary condition in FDTD simulations to truncate\n a simulation domain and absorb outgoing radiation. However, many divergence issues are associated with the\n use of PML. One of the most common causes of a diverged simulation is structures inserted into PML at an angle.\n\n .. TODO links to absorber boundaries\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation.png\n\n Incorporating a dispersive material into the PML can also cause simulation divergence in certain scenarios.\n If your simulation lacks any structures inserted into the PML at an angle, but includes dispersive material\n in PML, it is advisable to substitute a nondispersive material for the dispersive material. Alternatively,\n if dispersion is necessary, switching from the :class:`PML` to :class:`Absorber` can effectively address the\n issue.\n\n The PML can effectively absorb outgoing radiation with minimum reflection as if the radiation just propagates\n into the free space. However, it\u2019s important to keep in mind that the PML only absorbs propagating fields. For\n evanescent fields, the PML can act as an amplification medium and cause a simulation to diverge. In Tidy3D,\n a warning will appear if the distance between a structure is smaller than half of a wavelength to prevent\n evanescent fields from leaking into PML. In most cases, the evanescent field will naturally die off within\n half a wavelength, but in some instances, a larger distance may be required.\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation1.png\n\n\n **References**\n\n .. [1] W.C. Chew and W.H. Weedon, Microwave and Optical Tech. Lett., 7 (13), 599,1994; S. Johnson, arXiv 2108.05348, 2021\n .. [2] Antonios Giannopoulos, IEEE Transactions on Antennas and Propagation, 56(9), 2995, 2008\n\nNote\n----\n\n For best results, structures that intersect with the PML or simulation edges should extend extend all the way\n through. In many such cases, an \u201cinfinite\u201d size ``td.inf`` can be used to define the size along that dimension.\n\nExample\n-------\n>>> pml = PML(num_layers=10)\n\nSee Also\n--------\n\n:class:`StablePML`:\n This PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PML", + "enum": [ + "PML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of standard PML.", + "default": 12, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "PML Parameters", + "description": "Parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "StablePML": { + "title": "StablePML", + "description": "Specifies a 'stable' PML along a single dimension.\nThis PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of 'stable' PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.0, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=5.0, alpha_order=1, alpha_min=0.0, alpha_max=0.9)\n 'Stable' parameters of the complex frequency-shifted absorption poles.\n\nExample\n-------\n>>> pml = StablePML(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "StablePML", + "enum": [ + "StablePML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of 'stable' PML.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Stable PML Parameters", + "description": "'Stable' parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.0, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 5.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.9 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "AbsorberParams": { + "title": "AbsorberParams", + "description": "Specifies parameters common to Absorbers and PMLs.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\n\nExample\n-------\n>>> params = AbsorberParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AbsorberParams", + "enum": [ + "AbsorberParams" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Absorber": { + "title": "Absorber", + "description": "Specifies an adiabatic absorber along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of absorber to add to + and - boundaries.\nparameters : AbsorberParams = AbsorberParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=6.4, type='AbsorberParams')\n Adiabatic absorber parameters.\n\nNotes\n-----\n\n This absorber is well-suited for dispersive materials intersecting with absorbing edges of the simulation at the\n expense of more layers.\n\n **Usage Caveats**\n\n Using absorber boundary is often a good remedy to resolve divergence issues related to :class:`PML`. The\n adiabatic absorber is a multilayer system with gradually increasing conductivity. The absorber usually has a\n larger undesired reflection compared to :class:`PML`. In practice, this small difference rarely matters,\n but is important to understand for simulations that require high accuracy.\n\n There are two possible sources for the reflection from absorbers. The first, and more common one, is that the\n ramping up of the conductivity is not sufficiently slow, which can be remedied by increasing the number of\n absorber layers (40 by default). The second one is that the absorption is not high enough, such that the\n light reaches the :class:`PEC` boundary at the end of the :class:`Absorber`, travels back through it,\n and is still not fully attenuated before re-entering the simulation region. If this is the case, increasing\n the maximum conductivity :class:`AbsorberParams` can help. In both cases, changing the order of the scaling\n of the conductivity (:attr:`tidy3d.AbsorberParams.sigma_order`) can also have an effect, but this is a more\n advanced setting that we typically do not recommend modifying.\n\nExample\n-------\n>>> pml = Absorber(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Absorber", + "enum": [ + "Absorber" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of absorber to add to + and - boundaries.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Absorber Parameters", + "description": "Adiabatic absorber parameters.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 6.4, + "type": "AbsorberParams" + }, + "allOf": [ + { + "$ref": "#/definitions/AbsorberParams" + } + ] + } + }, + "additionalProperties": false + }, + "BlochBoundary": { + "title": "BlochBoundary", + "description": "Specifies a Bloch boundary condition along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nbloch_vec : float\n Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.\n\nExample\n-------\n>>> bloch = BlochBoundary(bloch_vec=1)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "BlochBoundary", + "enum": [ + "BlochBoundary" + ], + "type": "string" + }, + "bloch_vec": { + "title": "Normalized Bloch vector component", + "description": "Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.", + "type": "number" + } + }, + "required": [ + "bloch_vec" + ], + "additionalProperties": false + }, + "Boundary": { + "title": "Boundary", + "description": "Boundary conditions at the minus and plus extents along a dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the plus side along a dimension.\nminus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the minus side along a dimension.\n\nNotes\n-----\n\n To specify individual boundary conditions along different dimensions, instead of :class:`BoundarySpec`,\n this class is used, which defines the ``plus`` and ``minus`` boundaries along a single\n dimension.\n\nExample\n-------\n>>> boundary = Boundary(plus = PML(), minus = PECBoundary())\n\nSee Also\n--------\n\n:class:`BoundarySpec`\n Specifies boundary conditions on each side of the domain and along each dimension.\n\n:class:`PML`\n A standard PML along a single dimension.\n\n**Notebooks**\n * `Setting up boundary conditions <../../notebooks/BoundaryConditions.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "plus": { + "title": "Plus BC", + "description": "Boundary condition on the plus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "minus": { + "title": "Minus BC", + "description": "Boundary condition on the minus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "type": { + "title": "Type", + "default": "Boundary", + "enum": [ + "Boundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "BoundarySpec": { + "title": "BoundarySpec", + "description": "Specifies boundary conditions on each side of the domain and along each dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nx : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\ny : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\nz : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\n\nNotes\n-----\n\n This :class:`BoundarySpec` object defines the boundary conditions applied on each of the 6 domain edges,\n and is provided as an input to the simulation.\n\n A :class:`BoundarySpec` consists of three :class:`Boundary` objects, each defining the boundaries on the plus\n and minus side of each dimension. In most cases, one just wants to specify whether there are absorbing\n :class:`PML` layers along any of the ``x``, ``y``, ``z`` dimensions. By default, ``tidy3d`` simulations have\n :class:`PML` boundaries on all sides.\n\n If we want to explicitly set the boundaries, we can use the :attr:`tidy3d.BoundarySpec.all_sides` method.\n This can be used to set any type of boundary condition on all sides of the simulation. We can also set\n :class:`PML` on specified sides only by calling the :attr:`tidy3d.BoundarySpec.pml` method, e.g. ``BoundarySpec.pml(\n x=False, y=False, z=False)``. This will put :class:`PML` along the dimensions defined as ``True``,\n and set periodic boundaries along the other dimensions.\n\n\nSee Also\n--------\n\n:class:`Boundary`\n Boundary conditions at the minus and plus extents along a dimension.\n\n**Notebooks**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures**\n * `Using FDTD to Compute a Transmission Spectrum `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "x": { + "title": "Boundary condition along x.", + "description": "Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "y": { + "title": "Boundary condition along y.", + "description": "Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "z": { + "title": "Boundary condition along z.", + "description": "Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "type": { + "title": "Type", + "default": "BoundarySpec", + "enum": [ + "BoundarySpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ApodizationSpec": { + "title": "ApodizationSpec", + "description": "Stores specifications for the apodizaton of frequency-domain monitors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstart : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the start apodization ends.\nend : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the end apodization begins.\nwidth : Optional[PositiveFloat] = None\n [units = sec]. Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.\n\nExample\n-------\n>>> apod_spec = ApodizationSpec(start=1, end=2, width=0.2)\n\n\n.. image:: ../../_static/img/apodization.png\n :width: 80%\n :align: center", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "start": { + "title": "Start Interval", + "description": "Defines the time at which the start apodization ends.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "end": { + "title": "End Interval", + "description": "Defines the time at which the end apodization begins.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "width": { + "title": "Apodization Width", + "description": "Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ApodizationSpec", + "enum": [ + "ApodizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityMonitor": { + "title": "PermittivityMonitor", + "description": ":class:`Monitor` that records the diagonal components of the complex-valued relative\npermittivity tensor in the frequency domain. The recorded data has the same shape as a\n:class:`.FieldMonitor` of the same geometry: the permittivity values are saved at the\nYee grid locations, and can be interpolated to any point inside the monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : Literal[False] = False\n Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n This field is ignored in this monitor.\n\nNotes\n-----\n\n If 2D materials are present, then the permittivity values correspond to the\n volumetric equivalent of the 2D materials.\n\n .. TODO add links to relevant areas\n\nExample\n-------\n>>> monitor = PermittivityMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='eps_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityMonitor", + "enum": [ + "PermittivityMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "This field is ignored in this monitor.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "UniformGrid": { + "title": "UniformGrid", + "description": "Uniform 1D grid. The most standard way to define a simulation is to use a constant grid size in each of the three directions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\n\nExample\n-------\n>>> grid_1d = UniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`QuasiUniformGrid`\n Specification for quasi-uniform grid along a given dimension.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Photonic crystal waveguide polarization filter <../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "UniformGrid", + "enum": [ + "UniformGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "CustomGrid": { + "title": "CustomGrid", + "description": "Custom 1D grid supplied as a list of grid cell sizes centered on the simulation center.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : Tuple[PositiveFloat, ...]\n [units = um]. An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.\ncustom_offset : Optional[float] = None\n [units = um]. The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.\n\nExample\n-------\n>>> grid_1d = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGrid", + "enum": [ + "CustomGrid" + ], + "type": "string" + }, + "dl": { + "title": "Customized grid sizes.", + "description": "An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.", + "units": "um", + "type": "array", + "items": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "custom_offset": { + "title": "Customized grid offset.", + "description": "The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.", + "units": "um", + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GradedMesher": { + "title": "GradedMesher", + "description": "Implements automatic nonuniform meshing with a set minimum steps per wavelength and\na graded mesh expanding from higher- to lower-resolution regions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GradedMesher", + "enum": [ + "GradedMesher" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AutoGrid": { + "title": "AutoGrid", + "description": "Specification for non-uniform grid along a given dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\nmin_steps_per_wvl : ConstrainedFloatValue = 10.0\n Minimal number of steps per wavelength in each medium.\nmin_steps_per_sim_size : ConstrainedFloatValue = 10.0\n Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.\n\nExample\n-------\n>>> grid_1d = AutoGrid(min_steps_per_wvl=16, max_scale=1.4)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`GridSpec`\n Collective grid specification for all three dimensions.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "AutoGrid", + "enum": [ + "AutoGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "min_steps_per_wvl": { + "title": "Minimal Number of Steps Per Wavelength", + "description": "Minimal number of steps per wavelength in each medium.", + "default": 10.0, + "minimum": 6.0, + "type": "number" + }, + "min_steps_per_sim_size": { + "title": "Minimal Number of Steps Per Simulation Domain Size", + "description": "Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.", + "default": 10.0, + "minimum": 1.0, + "type": "number" + } + }, + "additionalProperties": false + }, + "CustomGridBoundaries": { + "title": "CustomGridBoundaries", + "description": "Custom 1D grid supplied as a list of grid cell boundary coordinates.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncoords : ArrayLike[dtype=float, ndim=1]\n [units = um]. An array of grid boundary coordinates.\n\nExample\n-------\n>>> grid_1d = CustomGridBoundaries(coords=[-0.2, 0.0, 0.2, 0.4, 0.5, 0.6, 0.7])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGridBoundaries", + "enum": [ + "CustomGridBoundaries" + ], + "type": "string" + }, + "coords": { + "title": "Grid Boundary Coordinates", + "description": "An array of grid boundary coordinates.", + "units": "um", + "type": "ArrayLike" + } + }, + "required": [ + "coords" + ], + "additionalProperties": false + }, + "QuasiUniformGrid": { + "title": "QuasiUniformGrid", + "description": "Similar to :class:`UniformGrid` that generates uniform 1D grid, but grid positions\nare locally fine tuned to be snaped to snapping points and the edges of structure bounding boxes.\nInternally, it is using the same meshing method as :class:`AutoGrid`, but it ignores material information in\nfavor for a user-defined grid size.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\ndl : PositiveFloat\n [units = um]. Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.\n\nExample\n-------\n>>> grid_1d = QuasiUniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "QuasiUniformGrid", + "enum": [ + "QuasiUniformGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "MeshOverrideStructure": { + "title": "MeshOverrideStructure", + "description": "Defines an object that is only used in the process of generating the mesh.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : int = 0\n Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.\ndl : Tuple[PositiveFloat, PositiveFloat, PositiveFloat]\n [units = um]. Grid size along x, y, z directions.\nenforce : bool = False\n If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.\nshadow : bool = True\n In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.\ndrop_outside_sim : bool = True\n If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.\n\nNotes\n-----\n\n A :class:`MeshOverrideStructure` is a combination of geometry :class:`Geometry`,\n grid size along ``x``, ``y``, ``z`` directions, and a boolean on whether the override\n will be enforced.\n\nExample\n-------\n>>> from tidy3d import Box\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.", + "default": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "MeshOverrideStructure", + "enum": [ + "MeshOverrideStructure" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size along x, y, z directions.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + }, + "enforce": { + "title": "Enforce Grid Size", + "description": "If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.", + "default": false, + "type": "boolean" + }, + "shadow": { + "title": "Grid Size Choice In Structure Overlapping Region", + "description": "In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.", + "default": true, + "type": "boolean" + }, + "drop_outside_sim": { + "title": "Drop Structure Outside Simulation Domain", + "description": "If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "geometry", + "dl" + ], + "additionalProperties": false + }, + "GridRefinement": { + "title": "GridRefinement", + "description": "Specification for local mesh refinement that defines the grid step size and the number of grid\ncells in the refinement region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrefinement_factor : Optional[PositiveFloat] = None\n Refine grid step size in vacuum by this factor.\ndl : Optional[PositiveFloat] = None\n [units = um]. Grid step size in the refined region.\nnum_cells : PositiveInt = 3\n Number of grid cells in the refinement region.\n\nNote\n----\n\nIf both `refinement_factor` and `dl` are defined, the grid step size is upper bounded by the smaller value of the two.\nIf neither is defined, default `refinement_factor=2` is applied.\n\n\nExample\n-------\n>>> grid_refine = GridRefinement(refinement_factor = 2, num_cells = 7)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "refinement_factor": { + "title": "Mesh Refinement Factor", + "description": "Refine grid step size in vacuum by this factor.", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid step size in the refined region.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_cells": { + "title": "Number of Refined Grid Cells", + "description": "Number of grid cells in the refinement region.", + "default": 3, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "GridRefinement", + "enum": [ + "GridRefinement" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "CornerFinderSpec": { + "title": "CornerFinderSpec", + "description": "Specification for corner detection on a 2D plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmedium : Literal['metal', 'dielectric', 'all'] = metal\n Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.\nangle_threshold : ConstrainedFloatValue = 0.3141592653589793\n A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.\ndistance_threshold : Optional[PositiveFloat] = None\n If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.\nconcave_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nconvex_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nmixed_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "medium": { + "title": "Material Type For Corner Identification", + "description": "Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.", + "default": "metal", + "enum": [ + "metal", + "dielectric", + "all" + ], + "type": "string" + }, + "angle_threshold": { + "title": "Angle Threshold In Corner Identification", + "description": "A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.", + "default": 0.3141592653589793, + "exclusiveMaximum": 3.141592653589793, + "minimum": 0, + "type": "number" + }, + "distance_threshold": { + "title": "Distance Threshold In Corner Identification", + "description": "If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concave_resolution": { + "title": "Concave Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "convex_resolution": { + "title": "Convex Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mixed_resolution": { + "title": "Mixed Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "CornerFinderSpec", + "enum": [ + "CornerFinderSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LayerRefinementSpec": { + "title": "LayerRefinementSpec", + "description": "Specification for automatic mesh refinement and snapping in layered structures. Structure corners\non the cross section perpendicular to layer thickness direction can be automatically identified. Subsequently,\nmesh is snapped and refined around the corners. Mesh can also be refined and snapped around the bounds along\nthe layer thickness direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\naxis : Literal[0, 1, 2]\n Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).\nmin_steps_along_axis : Optional[PositiveFloat] = None\n If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.\nbounds_refinement : Optional[GridRefinement] = None\n If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.\nbounds_snapping : Optional[Literal['bounds', 'lower', 'upper', 'center']] = lower\n If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.\ncorner_finder : Optional[CornerFinderSpec] = CornerFinderSpec(attrs={}, medium='metal', angle_threshold=0.3141592653589793, distance_threshold=None, concave_resolution=None, convex_resolution=None, mixed_resolution=None, type='CornerFinderSpec')\n Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.\ncorner_snapping : bool = True\n If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.\ncorner_refinement : Optional[GridRefinement] = GridRefinement(attrs={}, refinement_factor=None, dl=None, num_cells=3, type='GridRefinement')\n If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. \nrefinement_inside_sim_only : bool = True\n If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.\ngap_meshing_iters : NonNegativeInt = 1\n Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.\ndl_min_from_gap_width : bool = True\n Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.\n\nNote\n----\n\nCorner detection is performed on a 2D plane sitting in the middle of the layer. If the layer is finite\nalong inplane axes, corners outside the bounds are discarded.\n\nNote\n----\n\nThis class only takes effect when :class:`AutoGrid` is applied.\n\nExample\n-------\n>>> layer_spec = LayerRefinementSpec(axis=2, center=(0,0,0), size=(2, 3, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LayerRefinementSpec", + "enum": [ + "LayerRefinementSpec" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "min_steps_along_axis": { + "title": "Minimal Number Of Steps Along Axis", + "description": "If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.", + "exclusiveMinimum": 0, + "type": "number" + }, + "bounds_refinement": { + "title": "Mesh Refinement Factor Around Layer Bounds", + "description": "If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.", + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "bounds_snapping": { + "title": "Placing Grid Snapping Point Along Axis", + "description": "If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.", + "default": "lower", + "enum": [ + "bounds", + "lower", + "upper", + "center" + ], + "type": "string" + }, + "corner_finder": { + "title": "Inplane Corner Detection Specification", + "description": "Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.", + "default": { + "attrs": {}, + "medium": "metal", + "angle_threshold": 0.3141592653589793, + "distance_threshold": null, + "concave_resolution": null, + "convex_resolution": null, + "mixed_resolution": null, + "type": "CornerFinderSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/CornerFinderSpec" + } + ] + }, + "corner_snapping": { + "title": "Placing Grid Snapping Point At Corners", + "description": "If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.", + "default": true, + "type": "boolean" + }, + "corner_refinement": { + "title": "Inplane Mesh Refinement Factor Around Corners", + "description": "If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. ", + "default": { + "attrs": {}, + "refinement_factor": null, + "dl": null, + "num_cells": 3, + "type": "GridRefinement" + }, + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "refinement_inside_sim_only": { + "title": "Apply Refinement Only To Features Inside Simulation Domain", + "description": "If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.", + "default": true, + "type": "boolean" + }, + "gap_meshing_iters": { + "title": "Gap Meshing Iterations", + "description": "Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "dl_min_from_gap_width": { + "title": "Set ``dl_min`` from Estimated Gap Width", + "description": "Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "size", + "axis" + ], + "additionalProperties": false + }, + "GridSpec": { + "title": "GridSpec", + "description": "Collective grid specification for all three dimensions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngrid_x : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along x-axis\ngrid_y : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along y-axis\ngrid_z : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along z-axis\nwavelength : Optional[float] = None\n [units = um]. Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.\noverride_structures : Tuple[Annotated[Union[tidy3d.components.structure.Structure, tidy3d.components.structure.MeshOverrideStructure], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nsnapping_points : Tuple[tuple[Optional[float], Optional[float], Optional[float]], ...] = ()\n A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nlayer_refinement_specs : Tuple[LayerRefinementSpec, ...] = ()\n Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.\n\nExample\n-------\n>>> uniform = UniformGrid(dl=0.1)\n>>> custom = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])\n>>> auto = AutoGrid(min_steps_per_wvl=12)\n>>> grid_spec = GridSpec(grid_x=uniform, grid_y=custom, grid_z=auto, wavelength=1.5)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "grid_x": { + "title": "Grid specification along x-axis", + "description": "Grid specification along x-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_y": { + "title": "Grid specification along y-axis", + "description": "Grid specification along y-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_z": { + "title": "Grid specification along z-axis", + "description": "Grid specification along z-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "wavelength": { + "title": "Free-space wavelength", + "description": "Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.", + "units": "um", + "type": "number" + }, + "override_structures": { + "title": "Grid specification override structures", + "description": "A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Structure": "#/definitions/Structure", + "MeshOverrideStructure": "#/definitions/MeshOverrideStructure" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Structure" + }, + { + "$ref": "#/definitions/MeshOverrideStructure" + } + ] + } + }, + "snapping_points": { + "title": "Grid specification snapping_points", + "description": "A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + } + }, + "layer_refinement_specs": { + "title": "Mesh Refinement In Layered Structures", + "description": "Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/LayerRefinementSpec" + } + }, + "type": { + "title": "Type", + "default": "GridSpec", + "enum": [ + "GridSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LumpedResistor": { + "title": "LumpedResistor", + "description": "Class representing a rectangular lumped resistor. Lumped resistors are appended to the list\nof structures in the simulation as :class:`Medium2D` with the appropriate conductivity given\ntheir size and voltage axis.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nresistance : PositiveFloat\n Resistance value in ohms.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LumpedResistor", + "enum": [ + "LumpedResistor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "resistance" + ], + "additionalProperties": false + }, + "CoaxialLumpedResistor": { + "title": "CoaxialLumpedResistor", + "description": "Class representing a coaxial lumped resistor. Lumped resistors are appended to the list of\nstructures in the simulation as :class:`Medium2D` with the appropriate conductivity given their\nsize and geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nresistance : PositiveFloat\n Resistance value in ohms.\ncenter : Tuple[float, float, float] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nouter_diameter : PositiveFloat\n [units = um]. Diameter of the outer concentric circle.\ninner_diameter : PositiveFloat\n [units = um]. Diameter of the inner concentric circle.\nnormal_axis : Literal[0, 1, 2]\n Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "CoaxialLumpedResistor", + "enum": [ + "CoaxialLumpedResistor" + ], + "type": "string" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "outer_diameter": { + "title": "Outer Diameter", + "description": "Diameter of the outer concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "inner_diameter": { + "title": "Inner Diameter", + "description": "Diameter of the inner concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "normal_axis": { + "title": "Normal Axis", + "description": "Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + } + }, + "required": [ + "name", + "resistance", + "outer_diameter", + "inner_diameter", + "normal_axis" + ], + "additionalProperties": false + }, + "RLCNetwork": { + "title": "RLCNetwork", + "description": "Class for representing a simple network consisting of a resistor, capacitor, and inductor.\nProvides additional functionality for representing the network as an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nresistance : Optional[PositiveFloat] = None\n Resistance value in ohms.\ncapacitance : Optional[PositiveFloat] = None\n Capacitance value in farads.\ninductance : Optional[PositiveFloat] = None\n Inductance value in henrys.\nnetwork_topology : Literal['series', 'parallel'] = series\n Describes whether network elements are connected in ``series`` or ``parallel``.\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "capacitance": { + "title": "Capacitance", + "description": "Capacitance value in farads.", + "unit": "farad", + "exclusiveMinimum": 0, + "type": "number" + }, + "inductance": { + "title": "Inductance", + "description": "Inductance value in henrys.", + "unit": "henry", + "exclusiveMinimum": 0, + "type": "number" + }, + "network_topology": { + "title": "Network Topology", + "description": "Describes whether network elements are connected in ``series`` or ``parallel``.", + "default": "series", + "enum": [ + "series", + "parallel" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "RLCNetwork", + "enum": [ + "RLCNetwork" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AdmittanceNetwork": { + "title": "AdmittanceNetwork", + "description": "Class for representing a network consisting of an arbitrary number of resistors,\ncapacitors, and inductors. The network is represented in the Laplace domain\nas an admittance function. Provides additional functionality for representing the network\nas an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\na : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.\nb : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.\n\nNotes\n-----\n\n The network is described by the supplied coefficients as an admittance function that relates\n voltage to the current in the Laplace domain and is equivalent to a frequency-dependent\n complex conductivity :math:`\\sigma(\\omega)`.\n\n .. math::\n I(s) = Y(s)V(s)\n\n .. math::\n Y(s) = \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}\n\n An equivalent :class:`.PoleResidue` medium is constructed using an equivalent frequency-dependent\n complex permittivity defined as\n\n .. math::\n \\epsilon(s) = \\epsilon_\\infty - \\frac{\\Delta}{\\epsilon_0 s}\n \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}.\n\n The admittance is scaled depending on the geometric properties of the lumped element by\n the scaling factor :math:`\\Delta`. Implementation is based on the equivalent medium introduced\n by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> R = 50\n>>> C = 1e-12\n>>> a = (1, R * C) # Coefficients for an RC parallel network\n>>> b = (R, 0)\n>>> RC_parallel = AdmittanceNetwork(a=a,\n... b=b\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "a": { + "title": "Numerator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "b": { + "title": "Denominator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "type": { + "title": "Type", + "default": "AdmittanceNetwork", + "enum": [ + "AdmittanceNetwork" + ], + "type": "string" + } + }, + "required": [ + "a", + "b" + ], + "additionalProperties": false + }, + "LinearLumpedElement": { + "title": "LinearLumpedElement", + "description": "Lumped element representing a network consisting of resistors, capacitors, and inductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nnetwork : Union[RLCNetwork, AdmittanceNetwork]\n The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Switches between the different methods for distributing the lumped element over the grid.\n\n\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP\n>>> linear_element = LinearLumpedElement(\n... center=[0, 0, 0],\n... size=[2, 0, 3],\n... voltage_axis=0,\n... network=RL_series,\n... name=\"LumpedRL\"\n... ) # doctest: +SKIP\n\n\nSee Also\n--------\n\n**Notebooks:**\n * `Using lumped elements in Tidy3D simulations <../../notebooks/LinearLumpedElements.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearLumpedElement", + "enum": [ + "LinearLumpedElement" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "network": { + "title": "Network", + "description": "The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.", + "discriminator": { + "propertyName": "type", + "mapping": { + "RLCNetwork": "#/definitions/RLCNetwork", + "AdmittanceNetwork": "#/definitions/AdmittanceNetwork" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/RLCNetwork" + }, + { + "$ref": "#/definitions/AdmittanceNetwork" + } + ] + }, + "dist_type": { + "title": "Distribute Type", + "description": "Switches between the different methods for distributing the lumped element over the grid.", + "default": "on", + "enum": [ + "off", + "laterally_only", + "on" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "network" + ], + "additionalProperties": false + }, + "Staircasing": { + "title": "Staircasing", + "description": "Apply staircasing scheme to material assignment of Yee grids on structure boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nFor PEC interface, the algorithm is based on:\n\n A. Taflove and S. C. Hagness, \"Computational electromagnetics: the\n finite-difference time-domain method\", Chapter 10.3 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Staircasing", + "enum": [ + "Staircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PolarizedAveraging": { + "title": "PolarizedAveraging", + "description": "Apply a polarized subpixel averaging method to dielectric boundaries, which\nis a phenomenological approximation of :class:`.ContourPathAveraging`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolarizedAveraging", + "enum": [ + "PolarizedAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContourPathAveraging": { + "title": "ContourPathAveraging", + "description": "Apply a contour-path subpixel averaging method to dielectric boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ContourPathAveraging", + "enum": [ + "ContourPathAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VolumetricAveraging": { + "title": "VolumetricAveraging", + "description": "Apply volumetric averaging scheme to material properties of Yee grids on structure boundaries.\nThe material property is averaged in the volume surrounding the Yee grid.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstaircase_normal_component : bool = True\n Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VolumetricAveraging", + "enum": [ + "VolumetricAveraging" + ], + "type": "string" + }, + "staircase_normal_component": { + "title": "Staircasing For Field Components Substantially Normal To Interface", + "description": "Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HeuristicPECStaircasing": { + "title": "HeuristicPECStaircasing", + "description": "Apply a variant of staircasing scheme to PEC boundaries: the electric field grid is set to PEC\nif the field is substantially parallel to the interface.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeuristicPECStaircasing", + "enum": [ + "HeuristicPECStaircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECConformal": { + "title": "PECConformal", + "description": "Apply a subpixel averaging method known as conformal mesh scheme to PEC boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.3\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.\n\nNote\n----\nThe algorithm is based on:\n\n S. Dey and R. Mittra, \"A locally conformal finite-difference\n time-domain (FDTD) algorithm for modeling three-dimensional\n perfectly conducting objects\",\n IEEE Microwave and Guided Wave Letters, 7(9), 273 (1997).\n\n S. Benkler, N. Chavannes and N. Kuster, \"A new 3-D conformal\n PEC FDTD scheme with user-defined geometric precision and derived\n stability criterion\",\n IEEE Transactions on Antennas and Propagation, 54(6), 1843 (2006).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PECConformal", + "enum": [ + "PECConformal" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.3, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SurfaceImpedance": { + "title": "SurfaceImpedance", + "description": "Apply 1st order (Leontovich) surface impedance boundary condition to\nstructure made of :class:`.LossyMetalMedium`.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.0\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedance", + "enum": [ + "SurfaceImpedance" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.0, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SubpixelSpec": { + "title": "SubpixelSpec", + "description": "Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndielectric : Union[Staircasing, PolarizedAveraging, ContourPathAveraging] = PolarizedAveraging(attrs={}, type='PolarizedAveraging')\n Subpixel averaging method applied to dielectric material interfaces.\nmetal : Union[Staircasing, VolumetricAveraging] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.\npec : Union[Staircasing, HeuristicPECStaircasing, PECConformal] = PECConformal(attrs={}, type='PECConformal', timestep_reduction=0.3, edge_singularity_correction=False)\n Subpixel averaging method applied to PEC structure interfaces.\npmc : Union[Staircasing, HeuristicPECStaircasing] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to PMC structure interfaces.\nlossy_metal : Union[Staircasing, VolumetricAveraging, SurfaceImpedance] = SurfaceImpedance(attrs={}, type='SurfaceImpedance', timestep_reduction=0.0, edge_singularity_correction=False)\n Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "dielectric": { + "title": "Subpixel Averaging Method For Dielectric Interfaces", + "description": "Subpixel averaging method applied to dielectric material interfaces.", + "default": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "PolarizedAveraging": "#/definitions/PolarizedAveraging", + "ContourPathAveraging": "#/definitions/ContourPathAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/PolarizedAveraging" + }, + { + "$ref": "#/definitions/ContourPathAveraging" + } + ] + }, + "metal": { + "title": "Subpixel Averaging Method For Metallic Interfaces", + "description": "Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + } + ] + }, + "pec": { + "title": "Subpixel Averaging Method For PEC Interfaces", + "description": "Subpixel averaging method applied to PEC structure interfaces.", + "default": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing", + "PECConformal": "#/definitions/PECConformal" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + }, + { + "$ref": "#/definitions/PECConformal" + } + ] + }, + "pmc": { + "title": "Subpixel Averaging Method For PMC Interfaces", + "description": "Subpixel averaging method applied to PMC structure interfaces.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + } + ] + }, + "lossy_metal": { + "title": "Subpixel Averaging Method for Lossy Metal Interfaces", + "description": "Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "default": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging", + "SurfaceImpedance": "#/definitions/SurfaceImpedance" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + }, + { + "$ref": "#/definitions/SurfaceImpedance" + } + ] + }, + "type": { + "title": "Type", + "default": "SubpixelSpec", + "enum": [ + "SubpixelSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ModeSpec": { + "title": "ModeSpec", + "description": "Stores specifications for the mode solver to find an electromagntic mode.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\nprecision : Literal['auto', 'single', 'double'] = double\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = central\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.\n\nNotes\n-----\n\n The :attr:`angle_theta` and :attr:`angle_phi` parameters define the injection axis as illustrated in the figure\n below, with respect to the axis normal to the mode plane (``x`` in the figure). Note that :attr:`angle_theta`\n must be smaller than :math:`\\frac{pi}{2}`. To inject in the backward direction, we can still use the\n ``direction`` parameter as also shown in the figure. Similarly, the mode amplitudes computed in mode monitors\n are defined w.r.t. the ``forward`` and ``backward`` directions as illustrated. Note, the planar axes are\n found by popping the injection axis from ``{x,y,z}``. For example, if injection axis is ``y``, the planar\n axes are ordered ``{x,z}``.\n\n .. image:: ../../notebooks/img/ring_modes.png\n\n The :attr:`bend_axis` is the axis normal to the plane in which the bend lies, (``z`` in the diagram below). In\n the mode specification, it is defined locally for the mode plane as one of the two axes tangential to the\n plane. In the case of bends that lie in the ``xy``-plane, the mode plane would be either in ``xz`` or in\n ``yz``, so in both cases the correct setting is ``bend_axis=1``, selecting the global ``z``. The\n ``bend_radius`` is counted from the center of the mode plane to the center of the curvature,\n along the tangential axis perpendicular to the bend axis. This radius can also be negative, if the center of\n the mode plane is smaller than the center of the bend.\n\n .. image:: ../../notebooks/img/mode_angled.png\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Introduction on tidy3d working principles <../../notebooks/Primer.html#Modes>`_\n * `Defining mode sources and monitors <../../notebooks/ModalSourcesMonitors.html>`_\n * `Injecting modes in bent and angled waveguides <../../notebooks/ModesBentAngled.html>`_\n * `Waveguide to ring coupling <../../notebooks/WaveguideToRingCoupling.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_modes": { + "title": "Number of modes", + "description": "Number of modes returned by mode solver.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "target_neff": { + "title": "Target effective index", + "description": "Guess for effective index of the mode.", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_pml": { + "title": "Number of PML layers", + "description": "Number of standard pml layers to add in the two tangential axes.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ] + }, + "filter_pol": { + "title": "Polarization filtering", + "description": "The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.", + "enum": [ + "te", + "tm" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "precision": { + "title": "single, double, or automatic precision in mode solver", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "double", + "enum": [ + "auto", + "single", + "double" + ], + "type": "string" + }, + "bend_radius": { + "title": "Bend radius", + "description": "A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.", + "units": "um", + "type": "number" + }, + "bend_axis": { + "title": "Bend axis", + "description": "Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).", + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "angle_rotation": { + "title": "Use fields rotation when angle_theta is not zero", + "description": "Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.", + "default": false, + "type": "boolean" + }, + "track_freq": { + "title": "Mode Tracking Frequency", + "description": "Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.", + "default": "central", + "enum": [ + "central", + "lowest", + "highest" + ], + "type": "string" + }, + "group_index_step": { + "title": "Frequency step for group index computation", + "description": "Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "default": false, + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "boolean" + } + ] + }, + "type": { + "title": "Type", + "default": "ModeSpec", + "enum": [ + "ModeSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "GaussianPulse": { + "title": "GaussianPulse", + "description": "Source time dependence that describes a Gaussian pulse.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : ConstrainedFloatValue = 5.0\n Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).\nremove_dc_component : bool = True\n Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.\n\nExample\n-------\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "GaussianPulse", + "enum": [ + "GaussianPulse" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).", + "default": 5.0, + "minimum": 2.5, + "type": "number" + }, + "remove_dc_component": { + "title": "Remove DC Component", + "description": "Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "freq0", + "fwidth" + ], + "additionalProperties": false + }, + "ContinuousWave": { + "title": "ContinuousWave", + "description": "Source time dependence that ramps up to continuous oscillation\nand holds until end of simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : ConstrainedFloatValue = 5.0\n Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).\n\nNote\n----\nField decay will not occur, so the simulation will run for the full ``run_time``.\nAlso, source normalization of frequency-domain monitors is not meaningful.\n\nExample\n-------\n>>> cw = ContinuousWave(freq0=200e12, fwidth=20e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWave", + "enum": [ + "ContinuousWave" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).", + "default": 5.0, + "minimum": 2.5, + "type": "number" + } + }, + "required": [ + "freq0", + "fwidth" + ], + "additionalProperties": false + }, + "TimeDataset": { + "title": "TimeDataset", + "description": "Dataset for storing a function of time.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nvalues : TimeDataArray\n Values as a function of time.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TimeDataset", + "enum": [ + "TimeDataset" + ], + "type": "string" + }, + "values": { + "title": "DataArray", + "description": "Values as a function of time.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + "CustomSourceTime": { + "title": "CustomSourceTime", + "description": "Custom source time dependence consisting of a real or complex envelope\nmodulated at a central frequency, as shown below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : float = 0.0\n Time delay of the envelope in units of 1 / (``2pi * fwidth``).\nsource_time_dataset : Optional[TimeDataset]\n Dataset for storing the envelope of the custom source time. This envelope will be modulated by a complex exponential at frequency ``freq0``.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t} \\cdot \\\n envelope(t - offset / (2 \\pi \\cdot fwidth))\n\nNote\n----\nDepending on the envelope, field decay may not occur.\nIf field decay does not occur, then the simulation will run for the full ``run_time``.\nAlso, if field decay does not occur, then source normalization of frequency-domain\nmonitors is not meaningful.\n\nNote\n----\nThe source time dependence is linearly interpolated to the simulation time steps.\nThe sampling rate should be sufficiently fast that this interpolation does not\nintroduce artifacts. The source time dependence should also start at zero and ramp up smoothly.\nThe first and last values of the envelope will be used for times that are out of range\nof the provided data.\n\nExample\n-------\n>>> cst = CustomSourceTime.from_values(freq0=1, fwidth=0.1,\n... values=np.linspace(0, 9, 10), dt=0.1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CustomSourceTime", + "enum": [ + "CustomSourceTime" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the envelope in units of 1 / (``2pi * fwidth``).", + "default": 0.0, + "type": "number" + }, + "source_time_dataset": { + "title": "Source time dataset", + "description": "Dataset for storing the envelope of the custom source time. This envelope will be modulated by a complex exponential at frequency ``freq0``.", + "allOf": [ + { + "$ref": "#/definitions/TimeDataset" + } + ] + } + }, + "required": [ + "freq0", + "fwidth", + "source_time_dataset" + ], + "additionalProperties": false + }, + "ModeSource": { + "title": "ModeSource", + "description": "Injects current source to excite modal profile on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nmode_index : NonNegativeInt = 0\n Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.\n\nNotes\n-----\n\n Using this mode source, it is possible selectively excite one of the guided modes of a waveguide. This can be\n computed in our eigenmode solver :class:`tidy3d.plugins.mode.ModeSolver` and implement the mode simulation in\n FDTD.\n\n Mode sources are normalized to inject exactly 1W of power at the central frequency.\n\n The modal source allows you to do directional excitation. Illustrated\n by the image below, the field is perfectly launched to the right of the source and there's zero field to the\n left of the source. Now you can contrast the behavior of the modal source with that of a dipole source. If\n you just put a dipole into the waveguide, well, you see quite a bit different in the field distribution.\n First of all, the dipole source is not directional launching. It launches waves in both directions. The\n second is that the polarization of the dipole is set to selectively excite a TE mode. But it takes some\n propagation distance before the mode settles into a perfect TE mode profile. During this process,\n there is radiation into the substrate.\n\n .. image:: ../../_static/img/mode_vs_dipole_source.png\n\n .. TODO improve links to other APIs functionality here.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> mode_spec = ModeSpec(target_neff=2.)\n>>> mode_source = ModeSource(\n... size=(10,10,0),\n... source_time=pulse,\n... mode_spec=mode_spec,\n... mode_index=1,\n... direction='-')\n\nSee Also\n--------\n\n:class:`tidy3d.plugins.mode.ModeSolver`:\n Interface for solving electromagnetic eigenmodes in a 2D plane with translational invariance in the third dimension.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `90 degree optical hybrid <../../notebooks/90OpticalHybrid.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "ModeSource", + "enum": [ + "ModeSource" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "mode_index": { + "title": "Mode Index", + "description": "Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.", + "default": 0, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "size", + "source_time", + "direction" + ], + "additionalProperties": false + }, + "ModeMonitor": { + "title": "ModeMonitor", + "description": ":class:`Monitor` that records amplitudes from modal decomposition of fields on plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\n\nNotes\n------\n\n The fields recorded by frequency monitors (and hence also mode monitors) are automatically\n normalized by the power amplitude spectrum of the source. For multiple sources, the user can\n select which source to use for the normalization too.\n\n We can also use the mode amplitudes recorded in the mode monitor to reveal the decomposition\n of the radiated power into forward- and backward-propagating modes, respectively.\n\n .. TODO give an example of how to extract the data from this mode.\n\n .. TODO add derivation in the notebook.\n\n .. TODO add link to method\n\n .. TODO add links to notebooks correspondingly\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')\n\nSee Also\n--------\n\n**Notebooks**:\n * `ModalSourcesMonitors <../../notebooks/ModalSourcesMonitors.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeMonitor", + "enum": [ + "ModeMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "store_fields_direction": { + "title": "Store Fields", + "description": "Propagation direction for the mode field profiles stored from mode solving.", + "enum": [ + "+", + "-" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "ModeSolverMonitor": { + "title": "ModeSolverMonitor", + "description": ":class:`Monitor` that stores the mode field profiles returned by the mode solver in the\nmonitor plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeSolverMonitor", + "enum": [ + "ModeSolverMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "store_fields_direction": { + "title": "Store Fields", + "description": "Propagation direction for the mode field profiles stored from mode solving.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "direction": { + "title": "Propagation Direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/schemas/README.md b/schemas/README.md new file mode 100644 index 0000000000..926261c883 --- /dev/null +++ b/schemas/README.md @@ -0,0 +1,3 @@ +# Tidy3D Python Client API Schemas + +This directory contains the `jsonschema` of the Tidy3D API classes that have GUI support. diff --git a/tidy3d/schema.json b/schemas/Simulation.json similarity index 90% rename from tidy3d/schema.json rename to schemas/Simulation.json index 7cba052abf..30bf4bb7bf 100644 --- a/tidy3d/schema.json +++ b/schemas/Simulation.json @@ -1,6 +1,6 @@ { "title": "Simulation", - "description": "Custom implementation of Maxwell\u2019s equations which represents the physical model to be solved using the FDTD\nmethod.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (no symmetry), ``1`` (even, i.e. 'PMC' symmetry) or ``-1`` (odd, i.e. 'PEC' symmetry). Note that the vectorial nature of the fields must be taken into account to correctly determine the symmetry value.\nsources : Tuple[Annotated[Union[tidy3d.components.source.current.UniformCurrentSource, tidy3d.components.source.current.PointDipole, tidy3d.components.source.field.GaussianBeam, tidy3d.components.source.field.AstigmaticGaussianBeam, tidy3d.components.source.field.ModeSource, tidy3d.components.source.field.PlaneWave, tidy3d.components.source.field.CustomFieldSource, tidy3d.components.source.current.CustomCurrentSource, tidy3d.components.source.field.TFSF], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of electric current sources injecting fields into the simulation.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), y=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), z=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides.\nmonitors : Tuple[Annotated[Union[tidy3d.components.monitor.FieldMonitor, tidy3d.components.monitor.FieldTimeMonitor, tidy3d.components.monitor.AuxFieldTimeMonitor, tidy3d.components.monitor.PermittivityMonitor, tidy3d.components.monitor.FluxMonitor, tidy3d.components.monitor.FluxTimeMonitor, tidy3d.components.monitor.ModeMonitor, tidy3d.components.monitor.ModeSolverMonitor, tidy3d.components.monitor.FieldProjectionAngleMonitor, tidy3d.components.monitor.FieldProjectionCartesianMonitor, tidy3d.components.monitor.FieldProjectionKSpaceMonitor, tidy3d.components.monitor.DiffractionMonitor, tidy3d.components.monitor.DirectivityMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions.\nversion : str = 2.8.4\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. \nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\ncourant : ConstrainedFloatValue = 0.99\n Normalized Courant stability factor that is no larger than 1 when CFL stability condition is met. It controls time step to spatial step ratio. Lower values lead to more stable simulations for dispersive materials, but result in longer simulation times.\nnormalize_index : Optional[NonNegativeInt] = 0\n Index of the source in the tuple of sources whose spectrum will be used to normalize the frequency-dependent data. If ``None``, the raw field data is returned unnormalized.\nshutoff : NonNegativeFloat = 1e-05\n Ratio of the instantaneous integrated E-field intensity to the maximum value at which the simulation will automatically terminate time stepping. Used to prevent extraneous run time of simulations with fully decayed fields. Set to ``0`` to disable this feature.\nrun_time : Union[PositiveFloat, RunTimeSpec]\n [units = sec]. Total electromagnetic evolution time in seconds. Note: If simulation 'shutoff' is specified, simulation will terminate early when shutoff condition met. Alternatively, user may supply a :class:`RunTimeSpec` to this field, which will auto-compute the ``run_time`` based on the contents of the spec. If this option is used, the evaluated ``run_time`` value is available in the ``Simulation._run_time`` property.\n\nNotes\n-----\n\n A ``Simulation`` defines a custom implementation of Maxwell's equations which represents the physical model\n to be solved using `the Finite-Difference Time-Domain (FDTD) method\n `_. ``tidy3d`` simulations\n run very quickly in the cloud through GPU parallelization.\n\n .. image:: ../../_static/img/field_update_fdtd.png\n :width: 50%\n :align: left\n\n FDTD is a method for simulating the interaction of electromagnetic waves with structures and materials. It is\n the most widely used method in photonics design. The Maxwell's\n equations implemented in the ``Simulation`` are solved per time-step in the order shown in this image.\n\n The simplified input to FDTD solver consists of the permittivity distribution defined by :attr:`structures`\n which describe the device and :attr:`sources` of electromagnetic excitation. This information is used to\n computate the time dynamics of the electric and magnetic fields in this system. From these time-domain\n results, frequency-domain information of the simulation can also be extracted, and used for device design and\n optimization.\n\n If you are new to the FDTD method, we recommend you get started with the `FDTD 101 Lecture Series\n `_\n\n **Dimensions Selection**\n\n By default, simulations are defined as 3D. To make the simulation 2D, we can just set the simulation\n :attr:`size` in one of the dimensions to be 0. However, note that we still have to define a grid size (eg.\n ``tidy3d.Simulation(size=[size_x, size_y, 0])``) and specify a periodic boundary condition in that direction.\n\n .. TODO sort out inheritance problem https://aware-moon.cloudvent.net/tidy3d/examples/notebooks/RingResonator/\n\n See further parameter explanations below.\n\nExample\n-------\n>>> from tidy3d import Sphere, Cylinder, PolySlab\n>>> from tidy3d import UniformCurrentSource, GaussianPulse\n>>> from tidy3d import FieldMonitor, FluxMonitor\n>>> from tidy3d import GridSpec, AutoGrid\n>>> from tidy3d import BoundarySpec, Boundary\n>>> from tidy3d import Medium\n>>> sim = Simulation(\n... size=(3.0, 3.0, 3.0),\n... grid_spec=GridSpec(\n... grid_x = AutoGrid(min_steps_per_wvl = 20),\n... grid_y = AutoGrid(min_steps_per_wvl = 20),\n... grid_z = AutoGrid(min_steps_per_wvl = 20)\n... ),\n... run_time=40e-11,\n... structures=[\n... Structure(\n... geometry=Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=Medium(permittivity=2.0),\n... ),\n... ],\n... sources=[\n... UniformCurrentSource(\n... size=(0, 0, 0),\n... center=(0, 0.5, 0),\n... polarization=\"Hx\",\n... source_time=GaussianPulse(\n... freq0=2e14,\n... fwidth=4e13,\n... ),\n... )\n... ],\n... monitors=[\n... FluxMonitor(size=(1, 1, 0), center=(0, 0, 0), freqs=[2e14, 2.5e14], name='flux'),\n... ],\n... symmetry=(0, 0, 0),\n... boundary_spec=BoundarySpec(\n... x = Boundary.pml(num_layers=20),\n... y = Boundary.pml(num_layers=30),\n... z = Boundary.periodic(),\n... ),\n... shutoff=1e-6,\n... courant=0.8,\n... subpixel=False,\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n * See nearly all notebooks for :class:`Simulation` applications.\n\n**Lectures:**\n * `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_\n\n**GUI:**\n * `FDTD Walkthrough `_", + "description": "Custom implementation of Maxwell\u2019s equations which represents the physical model to be solved using the FDTD\nmethod.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (no symmetry), ``1`` (even, i.e. 'PMC' symmetry) or ``-1`` (odd, i.e. 'PEC' symmetry). Note that the vectorial nature of the fields must be taken into account to correctly determine the symmetry value.\nsources : Tuple[Annotated[Union[tidy3d.components.source.current.UniformCurrentSource, tidy3d.components.source.current.PointDipole, tidy3d.components.source.field.GaussianBeam, tidy3d.components.source.field.AstigmaticGaussianBeam, tidy3d.components.source.field.ModeSource, tidy3d.components.source.field.PlaneWave, tidy3d.components.source.field.CustomFieldSource, tidy3d.components.source.current.CustomCurrentSource, tidy3d.components.source.field.TFSF], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of electric current sources injecting fields into the simulation.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), y=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), z=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides.\nmonitors : Tuple[Annotated[Union[tidy3d.components.monitor.FieldMonitor, tidy3d.components.monitor.FieldTimeMonitor, tidy3d.components.monitor.AuxFieldTimeMonitor, tidy3d.components.monitor.PermittivityMonitor, tidy3d.components.monitor.FluxMonitor, tidy3d.components.monitor.FluxTimeMonitor, tidy3d.components.monitor.ModeMonitor, tidy3d.components.monitor.ModeSolverMonitor, tidy3d.components.monitor.FieldProjectionAngleMonitor, tidy3d.components.monitor.FieldProjectionCartesianMonitor, tidy3d.components.monitor.FieldProjectionKSpaceMonitor, tidy3d.components.monitor.DiffractionMonitor, tidy3d.components.monitor.DirectivityMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. \nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\ncourant : ConstrainedFloatValue = 0.99\n Normalized Courant stability factor that is no larger than 1 when CFL stability condition is met. It controls time step to spatial step ratio. Lower values lead to more stable simulations for dispersive materials, but result in longer simulation times.\nprecision : Literal['hybrid', 'double'] = hybrid\n Floating point precision to use in the computations. By default, Tidy3D uses a hybrid approach that offers a good balance of speed and accuracy for almost all simulations. However, for large simulations (or simulations with a long run time), where very high accuracy is needed, the precision can be set to double everywhere. Note that this doubles the FlexCredit cost of the simulation.\nnormalize_index : Optional[NonNegativeInt] = 0\n Index of the source in the tuple of sources whose spectrum will be used to normalize the frequency-dependent data. If ``None``, the raw field data is returned unnormalized.\nshutoff : NonNegativeFloat = 1e-05\n Ratio of the instantaneous integrated E-field intensity to the maximum value at which the simulation will automatically terminate time stepping. Used to prevent extraneous run time of simulations with fully decayed fields. Set to ``0`` to disable this feature.\nrun_time : Union[PositiveFloat, RunTimeSpec]\n [units = sec]. Total electromagnetic evolution time in seconds. Note: If simulation 'shutoff' is specified, simulation will terminate early when shutoff condition met. Alternatively, user may supply a :class:`RunTimeSpec` to this field, which will auto-compute the ``run_time`` based on the contents of the spec. If this option is used, the evaluated ``run_time`` value is available in the ``Simulation._run_time`` property.\n\nNotes\n-----\n\n A ``Simulation`` defines a custom implementation of Maxwell's equations which represents the physical model\n to be solved using `the Finite-Difference Time-Domain (FDTD) method\n `_. ``tidy3d`` simulations\n run very quickly in the cloud through GPU parallelization.\n\n .. image:: ../../_static/img/field_update_fdtd.png\n :width: 50%\n :align: left\n\n FDTD is a method for simulating the interaction of electromagnetic waves with structures and materials. It is\n the most widely used method in photonics design. The Maxwell's\n equations implemented in the ``Simulation`` are solved per time-step in the order shown in this image.\n\n The simplified input to FDTD solver consists of the permittivity distribution defined by :attr:`structures`\n which describe the device and :attr:`sources` of electromagnetic excitation. This information is used to\n computate the time dynamics of the electric and magnetic fields in this system. From these time-domain\n results, frequency-domain information of the simulation can also be extracted, and used for device design and\n optimization.\n\n If you are new to the FDTD method, we recommend you get started with the `FDTD 101 Lecture Series\n `_\n\n **Dimensions Selection**\n\n By default, simulations are defined as 3D. To make the simulation 2D, we can just set the simulation\n :attr:`size` in one of the dimensions to be 0. However, note that we still have to define a grid size (eg.\n ``tidy3d.Simulation(size=[size_x, size_y, 0])``) and specify a periodic boundary condition in that direction.\n\n .. TODO sort out inheritance problem https://aware-moon.cloudvent.net/tidy3d/examples/notebooks/RingResonator/\n\n See further parameter explanations below.\n\nExample\n-------\n>>> from tidy3d import Sphere, Cylinder, PolySlab\n>>> from tidy3d import UniformCurrentSource, GaussianPulse\n>>> from tidy3d import FieldMonitor, FluxMonitor\n>>> from tidy3d import GridSpec, AutoGrid\n>>> from tidy3d import BoundarySpec, Boundary\n>>> from tidy3d import Medium\n>>> sim = Simulation(\n... size=(3.0, 3.0, 3.0),\n... grid_spec=GridSpec(\n... grid_x = AutoGrid(min_steps_per_wvl = 20),\n... grid_y = AutoGrid(min_steps_per_wvl = 20),\n... grid_z = AutoGrid(min_steps_per_wvl = 20)\n... ),\n... run_time=40e-11,\n... structures=[\n... Structure(\n... geometry=Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=Medium(permittivity=2.0),\n... ),\n... ],\n... sources=[\n... UniformCurrentSource(\n... size=(0, 0, 0),\n... center=(0, 0.5, 0),\n... polarization=\"Hx\",\n... source_time=GaussianPulse(\n... freq0=2e14,\n... fwidth=4e13,\n... ),\n... )\n... ],\n... monitors=[\n... FluxMonitor(size=(1, 1, 0), center=(0, 0, 0), freqs=[2e14, 2.5e14], name='flux'),\n... ],\n... symmetry=(0, 0, 0),\n... boundary_spec=BoundarySpec(\n... x = Boundary.pml(num_layers=20),\n... y = Boundary.pml(num_layers=30),\n... z = Boundary.periodic(),\n... ),\n... shutoff=1e-6,\n... courant=0.8,\n... subpixel=False,\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n * See nearly all notebooks for :class:`Simulation` applications.\n\n**Lectures:**\n * `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_\n\n**GUI:**\n * `FDTD Walkthrough `_", "type": "object", "properties": { "attrs": { @@ -149,6 +149,7 @@ "Medium": "#/definitions/Medium", "AnisotropicMedium": "#/definitions/AnisotropicMedium", "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", "PoleResidue": "#/definitions/PoleResidue", "Sellmeier": "#/definitions/Sellmeier", "Lorentz": "#/definitions/Lorentz", @@ -177,6 +178,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -587,7 +591,7 @@ "version": { "title": "Version", "description": "String specifying the front end version number.", - "default": "2.8.4", + "default": "2.9.0", "type": "string" }, "plot_length_units": { @@ -604,6 +608,16 @@ ], "type": "string" }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, "lumped_elements": { "title": "Lumped Elements", "description": "Tuple of lumped elements in the simulation. ", @@ -647,12 +661,18 @@ "pec": { "attrs": {}, "type": "PECConformal", - "timestep_reduction": 0.3 + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" }, "lossy_metal": { "attrs": {}, "type": "SurfaceImpedance", - "timestep_reduction": 0.0 + "timestep_reduction": 0.0, + "edge_singularity_correction": false }, "type": "SubpixelSpec" }, @@ -707,6 +727,16 @@ "maximum": 1.0, "type": "number" }, + "precision": { + "title": "Floating-point Precision", + "description": "Floating point precision to use in the computations. By default, Tidy3D uses a hybrid approach that offers a good balance of speed and accuracy for almost all simulations. However, for large simulations (or simulations with a long run time), where very high accuracy is needed, the precision can be set to double everywhere. Note that this doubles the FlexCredit cost of the simulation.", + "default": "hybrid", + "enum": [ + "hybrid", + "double" + ], + "type": "string" + }, "normalize_index": { "title": "Normalization index", "description": "Index of the source in the tuple of sources whose spectrum will be used to normalize the frequency-dependent data. If ``None``, the raw field data is returned unnormalized.", @@ -1355,7 +1385,7 @@ }, "SolidSpec": { "title": "SolidSpec", - "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : PositiveFloat\n [units = J/(kg*K)]. Volumetric heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", "type": "object", "properties": { "attrs": { @@ -1379,7 +1409,7 @@ }, "capacity": { "title": "Heat capacity", - "description": "Volumetric heat capacity in unit of J/(kg*K).", + "description": "Specific heat capacity in unit of J/(kg*K).", "units": "J/(kg*K)", "exclusiveMinimum": 0, "type": "number" @@ -1390,17 +1420,23 @@ "units": "W/(um*K)", "exclusiveMinimum": 0, "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" } }, "required": [ - "capacity", "conductivity" ], "additionalProperties": false }, "SolidMedium": { "title": "SolidMedium", - "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : PositiveFloat\n [units = J/(kg*K)]. Volumetric heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", "type": "object", "properties": { "attrs": { @@ -1424,7 +1460,7 @@ }, "capacity": { "title": "Heat capacity", - "description": "Volumetric heat capacity in unit of J/(kg*K).", + "description": "Specific heat capacity in unit of J/(kg*K).", "units": "J/(kg*K)", "exclusiveMinimum": 0, "type": "number" @@ -1435,10 +1471,16 @@ "units": "W/(um*K)", "exclusiveMinimum": 0, "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" } }, "required": [ - "capacity", "conductivity" ], "additionalProperties": false @@ -1651,7 +1693,7 @@ }, "HuraySurfaceRoughness": { "title": "HuraySurfaceRoughness", - "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[Tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", "type": "object", "properties": { "attrs": { @@ -1756,7 +1798,7 @@ }, "LossyMetalMedium": { "title": "LossyMetalMedium", - "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", "type": "object", "properties": { "attrs": { @@ -1907,6 +1949,13 @@ } ] }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, "fit_param": { "title": "Fitting Parameters For Surface Impedance", "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", @@ -1932,7 +1981,7 @@ }, "PoleResidue": { "title": "PoleResidue", - "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[Tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -2134,7 +2183,7 @@ }, "Sellmeier": { "title": "Sellmeier", - "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[Tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -2269,7 +2318,7 @@ }, "Lorentz": { "title": "Lorentz", - "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -2416,7 +2465,7 @@ }, "Debye": { "title": "Debye", - "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -2559,7 +2608,7 @@ }, "Drude": { "title": "Drude", - "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -2809,9 +2858,118 @@ }, "additionalProperties": false }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, "AnisotropicMedium": { "title": "AnisotropicMedium", - "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", "type": "object", "properties": { "attrs": { @@ -2927,7 +3085,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -2954,6 +3113,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] }, @@ -2970,7 +3132,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -2997,6 +3160,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] }, @@ -3013,7 +3179,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -3040,6 +3207,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] } @@ -3277,7 +3447,7 @@ }, "TriangularGridDataset": { "title": "TriangularGridDataset", - "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", "type": "object", "properties": { "attrs": { @@ -3312,6 +3482,45 @@ "title": "Point Values", "description": "Values stored at the grid points.", "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, { "title": "DataArray", "type": "xr.DataArray", @@ -3381,7 +3590,7 @@ }, "TetrahedralGridDataset": { "title": "TetrahedralGridDataset", - "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", "type": "object", "properties": { "attrs": { @@ -3416,6 +3625,45 @@ "title": "Point Values", "description": "Values stored at the grid points.", "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, { "title": "DataArray", "type": "xr.DataArray", @@ -3662,7 +3910,7 @@ }, "CustomPoleResidue": { "title": "CustomPoleResidue", - "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[Tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -3891,7 +4139,7 @@ }, "CustomSellmeier": { "title": "CustomSellmeier", - "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[Tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -4089,7 +4337,7 @@ }, "CustomLorentz": { "title": "CustomLorentz", - "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -4346,7 +4594,7 @@ }, "CustomDebye": { "title": "CustomDebye", - "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -4575,7 +4823,7 @@ }, "CustomDrude": { "title": "CustomDrude", - "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[Tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", "type": "object", "properties": { "attrs": { @@ -5704,7 +5952,7 @@ }, "PerturbationPoleResidue": { "title": "PerturbationPoleResidue", - "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[Tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[Tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", "type": "object", "properties": { "attrs": { @@ -6616,7 +6864,7 @@ }, "GeometryGroup": { "title": "GeometryGroup", - "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('Tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", "type": "object", "properties": { "attrs": { @@ -7083,7 +7331,7 @@ }, "AnisotropicMediumFromMedium2D": { "title": "AnisotropicMediumFromMedium2D", - "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", "type": "object", "properties": { "attrs": { @@ -7199,7 +7447,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -7226,6 +7475,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] }, @@ -7242,7 +7494,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -7269,6 +7522,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] }, @@ -7285,7 +7541,8 @@ "Lorentz": "#/definitions/Lorentz", "Debye": "#/definitions/Debye", "Drude": "#/definitions/Drude", - "PECMedium": "#/definitions/PECMedium" + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" } }, "oneOf": [ @@ -7312,6 +7569,9 @@ }, { "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" } ] } @@ -8227,7 +8487,7 @@ }, "SemiconductorMedium": { "title": "SemiconductorMedium", - "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, Tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, Tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", "type": "object", "properties": { "attrs": { @@ -8500,7 +8760,7 @@ }, "MultiPhysicsMedium": { "title": "MultiPhysicsMedium", - "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", "type": "object", "properties": { "attrs": { @@ -8527,6 +8787,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -8629,7 +8892,7 @@ }, "Structure": { "title": "Structure", - "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", "type": "object", "properties": { "attrs": { @@ -8712,6 +8975,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -8789,6 +9055,11 @@ } ] }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, "type": { "title": "Type", "default": "Structure", @@ -8807,6 +9078,7 @@ "Medium": "#/definitions/Medium", "AnisotropicMedium": "#/definitions/AnisotropicMedium", "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", "PoleResidue": "#/definitions/PoleResidue", "Sellmeier": "#/definitions/Sellmeier", "Lorentz": "#/definitions/Lorentz", @@ -8847,6 +9119,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -9528,7 +9803,7 @@ }, "GaussianBeam": { "title": "GaussianBeam", - "description": "Gaussian distribution on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_radius : PositiveFloat = 1.0\n [units = um]. Radius of the beam at the waist.\nwaist_distance : float = 0.0\n [units = um]. Distance from the beam waist along the propagation direction. A positive value means the waist is positioned behind the source, considering the propagation direction. For example, for a beam propagating in the ``+`` direction, a positive value of ``beam_distance`` means the beam waist is positioned in the ``-`` direction (behind the source). A negative value means the beam waist is in the ``+`` direction (in front of the source). For an angled source, the distance is defined along the rotated propagation direction.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = GaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_radius=1.0)\n\nNotes\n--------\nIf one wants the focus 'in front' of the source, a negative value of ``beam_distance`` is needed.\n\n.. image:: ../../_static/img/beam_waist.png\n :width: 30%\n :align: center\n\nSee Also\n--------\n\n**Notebooks**:\n * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_", + "description": "Gaussian distribution on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_radius : PositiveFloat = 1.0\n [units = um]. Radius of the beam at the waist.\nwaist_distance : float = 0.0\n [units = um]. Distance from the beam waist along the propagation direction. A positive value means the waist is positioned behind the source, considering the propagation direction. For example, for a beam propagating in the ``+`` direction, a positive value of ``beam_distance`` means the beam waist is positioned in the ``-`` direction (behind the source). A negative value means the beam waist is in the ``+`` direction (in front of the source). For an angled source, the distance is defined along the rotated propagation direction.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = GaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_radius=1.0)\n\nNotes\n--------\nIf one wants the focus 'in front' of the source, a negative value of ``beam_distance`` is needed.\n\n.. image:: ../../_static/img/beam_waist.png\n :width: 30%\n :align: center\n\nSee Also\n--------\n\n**Notebooks**:\n * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_", "type": "object", "properties": { "attrs": { @@ -9685,8 +9960,8 @@ }, "num_freqs": { "title": "Number of Frequency Points", - "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", - "default": 3, + "description": "Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, "minimum": 1, "maximum": 20, "type": "integer" @@ -9746,7 +10021,7 @@ }, "AstigmaticGaussianBeam": { "title": "AstigmaticGaussianBeam", - "description": "The simple astigmatic Gaussian distribution allows\nboth an elliptical intensity profile and different waist locations for the two principal axes\nof the ellipse. When equal waist sizes and equal waist distances are specified in the two\ndirections, this source becomes equivalent to :class:`GaussianBeam`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_sizes : Tuple[PositiveFloat, PositiveFloat] = (1.0, 1.0)\n [units = um]. Size of the beam at the waist in the local x and y directions.\nwaist_distances : Tuple[float, float] = (0.0, 0.0)\n [units = um]. Distance to the beam waist along the propagation direction for the waist sizes in the local x and y directions. When ``direction`` is ``+`` and ``waist_distances`` are positive, the waist is on the ``-`` side (behind) the source plane. When ``direction`` is ``+`` and ``waist_distances`` are negative, the waist is on the ``+`` side (in front) of the source plane.\n\nNotes\n-----\n\n This class implements the simple astigmatic Gaussian beam described in _`[1]`.\n\n **References**:\n\n .. [1] Kochkina et al., Applied Optics, vol. 52, issue 24, 2013.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = AstigmaticGaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_sizes=(1.0, 2.0),\n... waist_distances = (3.0, 4.0))", + "description": "The simple astigmatic Gaussian distribution allows\nboth an elliptical intensity profile and different waist locations for the two principal axes\nof the ellipse. When equal waist sizes and equal waist distances are specified in the two\ndirections, this source becomes equivalent to :class:`GaussianBeam`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_sizes : Tuple[PositiveFloat, PositiveFloat] = (1.0, 1.0)\n [units = um]. Size of the beam at the waist in the local x and y directions.\nwaist_distances : Tuple[float, float] = (0.0, 0.0)\n [units = um]. Distance to the beam waist along the propagation direction for the waist sizes in the local x and y directions. When ``direction`` is ``+`` and ``waist_distances`` are positive, the waist is on the ``-`` side (behind) the source plane. When ``direction`` is ``+`` and ``waist_distances`` are negative, the waist is on the ``+`` side (in front) of the source plane.\n\nNotes\n-----\n\n This class implements the simple astigmatic Gaussian beam described in _`[1]`.\n\n **References**:\n\n .. [1] Kochkina et al., Applied Optics, vol. 52, issue 24, 2013.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = AstigmaticGaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_sizes=(1.0, 2.0),\n... waist_distances = (3.0, 4.0))", "type": "object", "properties": { "attrs": { @@ -9903,8 +10178,8 @@ }, "num_freqs": { "title": "Number of Frequency Points", - "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", - "default": 3, + "description": "Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, "minimum": 1, "maximum": 20, "type": "integer" @@ -9991,7 +10266,7 @@ }, "ModeSpec": { "title": "ModeSpec", - "description": "Stores specifications for the mode solver to find an electromagntic mode.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\nprecision : Literal['auto', 'single', 'double'] = auto\n The solver will be faster and using less memory under single precision, but more accurate under double precision. With the default ``'auto'``, apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = central\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.\n\nNotes\n-----\n\n The :attr:`angle_theta` and :attr:`angle_phi` parameters define the injection axis as illustrated in the figure\n below, with respect to the axis normal to the mode plane (``x`` in the figure). Note that :attr:`angle_theta`\n must be smaller than :math:`\\frac{pi}{2}`. To inject in the backward direction, we can still use the\n ``direction`` parameter as also shown in the figure. Similarly, the mode amplitudes computed in mode monitors\n are defined w.r.t. the ``forward`` and ``backward`` directions as illustrated. Note, the planar axes are\n found by popping the injection axis from ``{x,y,z}``. For example, if injection axis is ``y``, the planar\n axes are ordered ``{x,z}``.\n\n .. image:: ../../notebooks/img/ring_modes.png\n\n The :attr:`bend_axis` is the axis normal to the plane in which the bend lies, (``z`` in the diagram below). In\n the mode specification, it is defined locally for the mode plane as one of the two axes tangential to the\n plane. In the case of bends that lie in the ``xy``-plane, the mode plane would be either in ``xz`` or in\n ``yz``, so in both cases the correct setting is ``bend_axis=1``, selecting the global ``z``. The\n ``bend_radius`` is counted from the center of the mode plane to the center of the curvature,\n along the tangential axis perpendicular to the bend axis. This radius can also be negative, if the center of\n the mode plane is smaller than the center of the bend.\n\n .. image:: ../../notebooks/img/mode_angled.png\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Introduction on tidy3d working principles <../../notebooks/Primer.html#Modes>`_\n * `Defining mode sources and monitors <../../notebooks/ModalSourcesMonitors.html>`_\n * `Injecting modes in bent and angled waveguides <../../notebooks/ModesBentAngled.html>`_\n * `Waveguide to ring coupling <../../notebooks/WaveguideToRingCoupling.html>`_", + "description": "Stores specifications for the mode solver to find an electromagntic mode.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\nprecision : Literal['auto', 'single', 'double'] = double\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = central\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.\n\nNotes\n-----\n\n The :attr:`angle_theta` and :attr:`angle_phi` parameters define the injection axis as illustrated in the figure\n below, with respect to the axis normal to the mode plane (``x`` in the figure). Note that :attr:`angle_theta`\n must be smaller than :math:`\\frac{pi}{2}`. To inject in the backward direction, we can still use the\n ``direction`` parameter as also shown in the figure. Similarly, the mode amplitudes computed in mode monitors\n are defined w.r.t. the ``forward`` and ``backward`` directions as illustrated. Note, the planar axes are\n found by popping the injection axis from ``{x,y,z}``. For example, if injection axis is ``y``, the planar\n axes are ordered ``{x,z}``.\n\n .. image:: ../../notebooks/img/ring_modes.png\n\n The :attr:`bend_axis` is the axis normal to the plane in which the bend lies, (``z`` in the diagram below). In\n the mode specification, it is defined locally for the mode plane as one of the two axes tangential to the\n plane. In the case of bends that lie in the ``xy``-plane, the mode plane would be either in ``xz`` or in\n ``yz``, so in both cases the correct setting is ``bend_axis=1``, selecting the global ``z``. The\n ``bend_radius`` is counted from the center of the mode plane to the center of the curvature,\n along the tangential axis perpendicular to the bend axis. This radius can also be negative, if the center of\n the mode plane is smaller than the center of the bend.\n\n .. image:: ../../notebooks/img/mode_angled.png\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Introduction on tidy3d working principles <../../notebooks/Primer.html#Modes>`_\n * `Defining mode sources and monitors <../../notebooks/ModalSourcesMonitors.html>`_\n * `Injecting modes in bent and angled waveguides <../../notebooks/ModesBentAngled.html>`_\n * `Waveguide to ring coupling <../../notebooks/WaveguideToRingCoupling.html>`_", "type": "object", "properties": { "attrs": { @@ -10059,8 +10334,8 @@ }, "precision": { "title": "single, double, or automatic precision in mode solver", - "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. With the default ``'auto'``, apply double precision if the simulation contains a good conductor, single precision otherwise.", - "default": "auto", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "double", "enum": [ "auto", "single", @@ -10127,7 +10402,7 @@ }, "ModeSource": { "title": "ModeSource", - "description": "Injects current source to excite modal profile on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of injected field. A Chebyshev interpolation is used, thus, only a small number of points, i.e., less than 20, is typically sufficient to obtain converged results.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='auto', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nmode_index : NonNegativeInt = 0\n Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.\n\nNotes\n-----\n\n Using this mode source, it is possible selectively excite one of the guided modes of a waveguide. This can be\n computed in our eigenmode solver :class:`tidy3d.plugins.mode.ModeSolver` and implement the mode simulation in\n FDTD.\n\n Mode sources are normalized to inject exactly 1W of power at the central frequency.\n\n The modal source allows you to do directional excitation. Illustrated\n by the image below, the field is perfectly launched to the right of the source and there's zero field to the\n left of the source. Now you can contrast the behavior of the modal source with that of a dipole source. If\n you just put a dipole into the waveguide, well, you see quite a bit different in the field distribution.\n First of all, the dipole source is not directional launching. It launches waves in both directions. The\n second is that the polarization of the dipole is set to selectively excite a TE mode. But it takes some\n propagation distance before the mode settles into a perfect TE mode profile. During this process,\n there is radiation into the substrate.\n\n .. image:: ../../_static/img/mode_vs_dipole_source.png\n\n .. TODO improve links to other APIs functionality here.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> mode_spec = ModeSpec(target_neff=2.)\n>>> mode_source = ModeSource(\n... size=(10,10,0),\n... source_time=pulse,\n... mode_spec=mode_spec,\n... mode_index=1,\n... direction='-')\n\nSee Also\n--------\n\n:class:`tidy3d.plugins.mode.ModeSolver`:\n Interface for solving electromagnetic eigenmodes in a 2D plane with translational invariance in the third dimension.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `90 degree optical hybrid <../../notebooks/90OpticalHybrid.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "description": "Injects current source to excite modal profile on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nmode_index : NonNegativeInt = 0\n Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.\n\nNotes\n-----\n\n Using this mode source, it is possible selectively excite one of the guided modes of a waveguide. This can be\n computed in our eigenmode solver :class:`tidy3d.plugins.mode.ModeSolver` and implement the mode simulation in\n FDTD.\n\n Mode sources are normalized to inject exactly 1W of power at the central frequency.\n\n The modal source allows you to do directional excitation. Illustrated\n by the image below, the field is perfectly launched to the right of the source and there's zero field to the\n left of the source. Now you can contrast the behavior of the modal source with that of a dipole source. If\n you just put a dipole into the waveguide, well, you see quite a bit different in the field distribution.\n First of all, the dipole source is not directional launching. It launches waves in both directions. The\n second is that the polarization of the dipole is set to selectively excite a TE mode. But it takes some\n propagation distance before the mode settles into a perfect TE mode profile. During this process,\n there is radiation into the substrate.\n\n .. image:: ../../_static/img/mode_vs_dipole_source.png\n\n .. TODO improve links to other APIs functionality here.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> mode_spec = ModeSpec(target_neff=2.)\n>>> mode_source = ModeSource(\n... size=(10,10,0),\n... source_time=pulse,\n... mode_spec=mode_spec,\n... mode_index=1,\n... direction='-')\n\nSee Also\n--------\n\n:class:`tidy3d.plugins.mode.ModeSolver`:\n Interface for solving electromagnetic eigenmodes in a 2D plane with translational invariance in the third dimension.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `90 degree optical hybrid <../../notebooks/90OpticalHybrid.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", "type": "object", "properties": { "attrs": { @@ -10284,10 +10559,10 @@ }, "num_freqs": { "title": "Number of Frequency Points", - "description": "Number of points used to approximate the frequency dependence of injected field. A Chebyshev interpolation is used, thus, only a small number of points, i.e., less than 20, is typically sufficient to obtain converged results.", + "description": "Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", "default": 1, "minimum": 1, - "maximum": 99, + "maximum": 20, "type": "integer" }, "direction": { @@ -10313,7 +10588,7 @@ "filter_pol": null, "angle_theta": 0.0, "angle_phi": 0.0, - "precision": "auto", + "precision": "double", "bend_radius": null, "bend_axis": null, "angle_rotation": false, @@ -10388,7 +10663,7 @@ }, "PlaneWave": { "title": "PlaneWave", - "description": "Uniform current distribution on an infinite extent plane. One element of size must be zero.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nangular_spec : Union[FixedInPlaneKSpec, FixedAngleSpec] = FixedInPlaneKSpec(attrs={}, type='FixedInPlaneKSpec')\n Specification of plane wave propagation direction dependence on wavelength.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> pw_source = PlaneWave(size=(inf,0,inf), source_time=pulse, pol_angle=0.1, direction='+')\n\nSee Also\n--------\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__", + "description": "Uniform current distribution on an infinite extent plane. One element of size must be zero.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband plane waves. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nangular_spec : Union[FixedInPlaneKSpec, FixedAngleSpec] = FixedInPlaneKSpec(attrs={}, type='FixedInPlaneKSpec')\n Specification of plane wave propagation direction dependence on wavelength.\n\nNotes\n-----\n\n For oblique incidence, there are two possible settings: fixed in-plane k-vector and fixed-angle mode.\n The first requires Bloch periodic boundary conditions, and the incidence angle is exact only at the central wavelength.\n The latter requires periodic boundary conditions and maintains a constant propagation angle over a broadband spectrum.\n For more information and important notes, see this example: `Broadband PlaneWave With Constant Oblique Incident Angle `_.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> pw_source = PlaneWave(size=(inf,0,inf), source_time=pulse, pol_angle=0.1, direction='+')\n\nSee Also\n--------\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__", "type": "object", "properties": { "attrs": { @@ -10545,7 +10820,7 @@ }, "num_freqs": { "title": "Number of Frequency Points", - "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", + "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband plane waves. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", "default": 3, "minimum": 1, "maximum": 20, @@ -11080,7 +11355,7 @@ }, "TFSF": { "title": "TFSF", - "description": "Total-field scattered-field (TFSF) source that can inject a plane wave in a finite region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\ninjection_axis : Literal[0, 1, 2]\n Specifies the injection axis. The plane of incidence is defined via this ``injection_axis`` and the ``direction``. The popagation axis is defined with respect to the ``injection_axis`` by ``angle_theta`` and ``angle_phi``.\n\nNotes\n-----\n\n The TFSF source injects :math:`1 W` of power per :math:`\\mu m^2` of source area along the :attr:`injection_axis`.\n Hence, the normalization for the incident field is :math:`|E_0|^2 = \\frac{2}{c\\epsilon_0}`, for any source size.\n Note that in the case of angled incidence, the same power is injected along the source's :attr:`injection_axis`,\n and not the propagation direction. This allows computing scattering and absorption cross-sections\n without the need for additional normalization.\n\n The TFSF source allows specifying a box region into which a plane wave is injected. Fields inside this region\n can be interpreted as the superposition of the incident field and the scattered field due to any scatterers\n present in the simulation domain. The fields at the edges of the TFSF box are modified at each time step such\n that the incident field is cancelled out, so that all fields outside the TFSF box are scattered fields only.\n This is useful in scenarios where one is interested in computing scattered fields only, for example when\n computing scattered cross-sections of various objects.\n\n It is important to note that when a non-uniform grid is used in the directions transverse to the\n :attr:`injection_axis` of the TFSF source, the suppression of the incident field outside the TFSF box may not be as\n close to zero as in the case of a uniform grid. Because of this, a warning may be issued when nonuniform grid\n TFSF setup is detected. In some cases, however, the accuracy may be only weakly affected, and the warnings\n can be ignored.\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Nanoparticle Scattering <../../notebooks/PlasmonicNanoparticle.html>`_: To force a uniform grid in the TFSF region and avoid the warnings, a mesh override structure can be used as illustrated here.", + "description": "Total-field scattered-field (TFSF) source that can inject a plane wave in a finite region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\ninjection_axis : Literal[0, 1, 2]\n Specifies the injection axis. The plane of incidence is defined via this ``injection_axis`` and the ``direction``. The popagation axis is defined with respect to the ``injection_axis`` by ``angle_theta`` and ``angle_phi``.\n\nNotes\n-----\n\n The TFSF source injects :math:`1 W` of power per :math:`\\mu m^2` of source area along the :attr:`injection_axis`.\n Hence, the normalization for the incident field is :math:`|E_0|^2 = \\frac{2}{c\\epsilon_0}`, for any source size.\n Note that in the case of angled incidence, the same power is injected along the source's :attr:`injection_axis`,\n and not the propagation direction. This allows computing scattering and absorption cross-sections\n without the need for additional normalization.\n\n The TFSF source allows specifying a box region into which a plane wave is injected. Fields inside this region\n can be interpreted as the superposition of the incident field and the scattered field due to any scatterers\n present in the simulation domain. The fields at the edges of the TFSF box are modified at each time step such\n that the incident field is cancelled out, so that all fields outside the TFSF box are scattered fields only.\n This is useful in scenarios where one is interested in computing scattered fields only, for example when\n computing scattered cross-sections of various objects.\n\n It is important to note that when a non-uniform grid is used in the directions transverse to the\n :attr:`injection_axis` of the TFSF source, the suppression of the incident field outside the TFSF box may not be as\n close to zero as in the case of a uniform grid. Because of this, a warning may be issued when nonuniform grid\n TFSF setup is detected. In some cases, however, the accuracy may be only weakly affected, and the warnings\n can be ignored.\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Nanoparticle Scattering <../../notebooks/PlasmonicNanoparticle.html>`_: To force a uniform grid in the TFSF region and avoid the warnings, a mesh override structure can be used as illustrated here.", "type": "object", "properties": { "attrs": { @@ -11237,8 +11512,8 @@ }, "num_freqs": { "title": "Number of Frequency Points", - "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband sources. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", - "default": 3, + "description": "Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, "minimum": 1, "maximum": 20, "type": "integer" @@ -11488,7 +11763,7 @@ "title": "Number of Layers", "description": "Number of layers of standard PML.", "default": 12, - "minimum": 6, + "minimum": 1, "type": "integer" }, "parameters": { @@ -11544,7 +11819,7 @@ "title": "Number of Layers", "description": "Number of layers of 'stable' PML.", "default": 40, - "minimum": 6, + "minimum": 1, "type": "integer" }, "parameters": { @@ -11645,7 +11920,7 @@ "title": "Number of Layers", "description": "Number of layers of absorber to add to + and - boundaries.", "default": 40, - "minimum": 6, + "minimum": 1, "type": "integer" }, "parameters": { @@ -12060,7 +12335,7 @@ }, "FieldMonitor": { "title": "FieldMonitor", - "description": ":class:`Monitor` that records electromagnetic fields in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\n\nNotes\n-----\n\n :class:`FieldMonitor` objects operate by running a discrete Fourier transform of the fields at a given set of\n frequencies to perform the calculation \u201cin-place\u201d with the time stepping. :class:`FieldMonitor` objects are\n useful for investigating the steady-state field distribution in 2D and 3D regions of the simulation.\n\nExample\n-------\n>>> monitor = FieldMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... fields=['Hx'],\n... freqs=[250e12, 300e12],\n... name='steady_state_monitor',\n... colocate=True)\n\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n\n**Lectures**\n\n* `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.", + "description": ":class:`Monitor` that records electromagnetic fields in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\n\nNotes\n-----\n\n :class:`FieldMonitor` objects operate by running a discrete Fourier transform of the fields at a given set of\n frequencies to perform the calculation \u201cin-place\u201d with the time stepping. :class:`FieldMonitor` objects are\n useful for investigating the steady-state field distribution in 2D and 3D regions of the simulation.\n\nExample\n-------\n>>> monitor = FieldMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... fields=['Hx'],\n... freqs=[250e12, 300e12],\n... name='steady_state_monitor',\n... colocate=True)\n\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n\n**Lectures**\n\n* `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.", "type": "object", "properties": { "attrs": { @@ -12719,7 +12994,7 @@ }, "PermittivityMonitor": { "title": "PermittivityMonitor", - "description": ":class:`Monitor` that records the diagonal components of the complex-valued relative\npermittivity tensor in the frequency domain. The recorded data has the same shape as a\n:class:`.FieldMonitor` of the same geometry: the permittivity values are saved at the\nYee grid locations, and can be interpolated to any point inside the monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : Literal[False] = False\n Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n This field is ignored in this monitor.\n\nNotes\n-----\n\n If 2D materials are present, then the permittivity values correspond to the\n volumetric equivalent of the 2D materials.\n\n .. TODO add links to relevant areas\n\nExample\n-------\n>>> monitor = PermittivityMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='eps_monitor')", + "description": ":class:`Monitor` that records the diagonal components of the complex-valued relative\npermittivity tensor in the frequency domain. The recorded data has the same shape as a\n:class:`.FieldMonitor` of the same geometry: the permittivity values are saved at the\nYee grid locations, and can be interpolated to any point inside the monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : Literal[False] = False\n Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n This field is ignored in this monitor.\n\nNotes\n-----\n\n If 2D materials are present, then the permittivity values correspond to the\n volumetric equivalent of the 2D materials.\n\n .. TODO add links to relevant areas\n\nExample\n-------\n>>> monitor = PermittivityMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='eps_monitor')", "type": "object", "properties": { "attrs": { @@ -12929,7 +13204,7 @@ }, "FluxMonitor": { "title": "FluxMonitor", - "description": ":class:`Monitor` that records power flux in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\n\nNotes\n-----\n\n If the monitor geometry is a 2D box, the total flux through this plane is returned, with a\n positive sign corresponding to power flow in the positive direction along the axis normal to\n the plane. If the geometry is a 3D box, the total power coming out of the box is returned by\n integrating the flux over all box surfaces (except the ones defined in ``exclude_surfaces``).\n\nExample\n-------\n>>> monitor = FluxMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... name='flux_monitor')\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../notebooks/THzDemultiplexerFilter.html>`_", + "description": ":class:`Monitor` that records power flux in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\n\nNotes\n-----\n\n If the monitor geometry is a 2D box, the total flux through this plane is returned, with a\n positive sign corresponding to power flow in the positive direction along the axis normal to\n the plane. If the geometry is a 3D box, the total power coming out of the box is returned by\n integrating the flux over all box surfaces (except the ones defined in ``exclude_surfaces``).\n\nExample\n-------\n>>> monitor = FluxMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... name='flux_monitor')\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../notebooks/THzDemultiplexerFilter.html>`_", "type": "object", "properties": { "attrs": { @@ -13399,7 +13674,7 @@ }, "ModeMonitor": { "title": "ModeMonitor", - "description": ":class:`Monitor` that records amplitudes from modal decomposition of fields on plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='auto', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\n\nNotes\n------\n\n The fields recorded by frequency monitors (and hence also mode monitors) are automatically\n normalized by the power amplitude spectrum of the source. For multiple sources, the user can\n select which source to use for the normalization too.\n\n We can also use the mode amplitudes recorded in the mode monitor to reveal the decomposition\n of the radiated power into forward- and backward-propagating modes, respectively.\n\n .. TODO give an example of how to extract the data from this mode.\n\n .. TODO add derivation in the notebook.\n\n .. TODO add link to method\n\n .. TODO add links to notebooks correspondingly\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')\n\nSee Also\n--------\n\n**Notebooks**:\n * `ModalSourcesMonitors <../../notebooks/ModalSourcesMonitors.html>`_", + "description": ":class:`Monitor` that records amplitudes from modal decomposition of fields on plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\n\nNotes\n------\n\n The fields recorded by frequency monitors (and hence also mode monitors) are automatically\n normalized by the power amplitude spectrum of the source. For multiple sources, the user can\n select which source to use for the normalization too.\n\n We can also use the mode amplitudes recorded in the mode monitor to reveal the decomposition\n of the radiated power into forward- and backward-propagating modes, respectively.\n\n .. TODO give an example of how to extract the data from this mode.\n\n .. TODO add derivation in the notebook.\n\n .. TODO add link to method\n\n .. TODO add links to notebooks correspondingly\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')\n\nSee Also\n--------\n\n**Notebooks**:\n * `ModalSourcesMonitors <../../notebooks/ModalSourcesMonitors.html>`_", "type": "object", "properties": { "attrs": { @@ -13616,7 +13891,7 @@ "filter_pol": null, "angle_theta": 0.0, "angle_phi": 0.0, - "precision": "auto", + "precision": "double", "bend_radius": null, "bend_axis": null, "angle_rotation": false, @@ -13649,7 +13924,7 @@ }, "ModeSolverMonitor": { "title": "ModeSolverMonitor", - "description": ":class:`Monitor` that stores the mode field profiles returned by the mode solver in the\nmonitor plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='auto', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')", + "description": ":class:`Monitor` that stores the mode field profiles returned by the mode solver in the\nmonitor plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')", "type": "object", "properties": { "attrs": { @@ -13866,7 +14141,7 @@ "filter_pol": null, "angle_theta": 0.0, "angle_phi": 0.0, - "precision": "auto", + "precision": "double", "bend_radius": null, "bend_axis": null, "angle_rotation": false, @@ -13933,7 +14208,7 @@ }, "FieldProjectionAngleMonitor": { "title": "FieldProjectionAngleMonitor", - "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them at given observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNotes\n-----\n\n .. TODO this needs an illustration\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` parameters define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`phi`, :attr:`theta`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n **Usage Caveats**\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the\n fields are propagating in a homogeneous medium. Therefore, one should use :class:`PML` / :class:`Absorber` as\n boundary conditions in the part of the domain where fields are projected.\n\n .. TODO why not add equation here\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases. For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. TODO TYPO FIX o that the approximations are not used, and the projection is accurate even just a few wavelengths away from the near field locations.\n\n By default, if no :attr:`proj_distance` was provided, the fields are projected to a distance of 1m.\n\n **Server-side field projection Application**\n\n Provide the :class:`FieldProjectionAngleMonitor` monitor as an input to the\n :class:`Simulation` object as one of its monitors. Now, we no longer need to provide a separate near-field\n :class:`FieldMonitor` - the near fields will automatically be recorded based on the size and location of the\n ``FieldProjectionAngleMonitor``. Note also that in some cases, the server-side computations may be slightly\n more accurate than client-side ones, because on the server, the near fields are not downsampled at all.\n\n We can re-project the already-computed far fields to a different distance away from the structure - we\n neither need to run another simulation nor re-run the :class:`FieldProjector`.\n\n **Far-Field Approximation Selection**\n\n .. TODO unsure if add on params?\n\n If the distance between the near and far field locations is\n much larger than the size of the device, one can typically set :attr:`far_field_approx` to\n ``True``, which will make use of the far-field approximation to speed up calculations.\n If the projection distance is comparable to the size of the device, we recommend setting\n :attr:`far_field_approx` to ``False``.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO Fix that image so remove right irrelevant side\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter :attr:`far_field_approx` to ``False`` in the\n ``FieldProjectionAngleMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include here inherited methods.\n\nExample\n-------\n>>> monitor = FieldProjectionAngleMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... phi=[0, np.pi/2],\n... theta=np.linspace(-np.pi/2, np.pi/2, 100),\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_: For far field projections in the context of perdiodic boundary conditions.", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them at given observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNotes\n-----\n\n .. TODO this needs an illustration\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` parameters define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`phi`, :attr:`theta`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n **Usage Caveats**\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the\n fields are propagating in a homogeneous medium. Therefore, one should use :class:`PML` / :class:`Absorber` as\n boundary conditions in the part of the domain where fields are projected.\n\n .. TODO why not add equation here\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases. For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. TODO TYPO FIX o that the approximations are not used, and the projection is accurate even just a few wavelengths away from the near field locations.\n\n By default, if no :attr:`proj_distance` was provided, the fields are projected to a distance of 1m.\n\n **Server-side field projection Application**\n\n Provide the :class:`FieldProjectionAngleMonitor` monitor as an input to the\n :class:`Simulation` object as one of its monitors. Now, we no longer need to provide a separate near-field\n :class:`FieldMonitor` - the near fields will automatically be recorded based on the size and location of the\n ``FieldProjectionAngleMonitor``. Note also that in some cases, the server-side computations may be slightly\n more accurate than client-side ones, because on the server, the near fields are not downsampled at all.\n\n We can re-project the already-computed far fields to a different distance away from the structure - we\n neither need to run another simulation nor re-run the :class:`FieldProjector`.\n\n **Far-Field Approximation Selection**\n\n .. TODO unsure if add on params?\n\n If the distance between the near and far field locations is\n much larger than the size of the device, one can typically set :attr:`far_field_approx` to\n ``True``, which will make use of the far-field approximation to speed up calculations.\n If the projection distance is comparable to the size of the device, we recommend setting\n :attr:`far_field_approx` to ``False``.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO Fix that image so remove right irrelevant side\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter :attr:`far_field_approx` to ``False`` in the\n ``FieldProjectionAngleMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include here inherited methods.\n\nExample\n-------\n>>> monitor = FieldProjectionAngleMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... phi=[0, np.pi/2],\n... theta=np.linspace(-np.pi/2, np.pi/2, 100),\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_: For far field projections in the context of perdiodic boundary conditions.", "type": "object", "properties": { "attrs": { @@ -14217,6 +14492,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -14324,7 +14602,7 @@ }, "FieldProjectionCartesianMonitor": { "title": "FieldProjectionCartesianMonitor", - "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on a Cartesian observation plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Signed distance of the projection plane along ``proj_axis``. from the plane containing ``local_origin``.\nx : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local x observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global y axis. When ``proj_axis`` is 1, this corresponds to the global x axis. When ``proj_axis`` is 2, this corresponds to the global x axis. \ny : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local y observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global z axis. When ``proj_axis`` is 1, this corresponds to the global z axis. When ``proj_axis`` is 2, this corresponds to the global y axis. \n\nNotes\n-----\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` fields define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`x`, :attr:`y`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n Here, :attr:`x` and :attr:`y`, correspond to a local coordinate system\n where the local ``z`` axis is defined by :attr:`proj_axis`: which is the axis normal to this monitor.\n\n **Far-Field Approximation Selection**\n\n If the distance between the near and far field locations is much larger than the size of the\n device, one can typically set :attr:`far_field_approx` to ``True``, which will make use of the\n far-field approximation to speed up calculations. If the projection distance is comparable\n to the size of the device, we recommend setting :attr:`far_field_approx` to ``False``,\n so that the approximations are not used, and the projection is accurate even just a few\n wavelengths away from the near field locations.\n\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO unsure if add on params?\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter ``far_field_approx=False`` in the\n ``FieldProjectionCartesianMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include this example\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a DiffractionMonitor.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionCartesianMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... x=[-1, 0, 1],\n... y=[-2, -1, 0, 1, 2],\n... proj_axis=2,\n... proj_distance=5,\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on a Cartesian observation plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Signed distance of the projection plane along ``proj_axis``. from the plane containing ``local_origin``.\nx : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local x observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global y axis. When ``proj_axis`` is 1, this corresponds to the global x axis. When ``proj_axis`` is 2, this corresponds to the global x axis. \ny : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local y observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global z axis. When ``proj_axis`` is 1, this corresponds to the global z axis. When ``proj_axis`` is 2, this corresponds to the global y axis. \n\nNotes\n-----\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` fields define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`x`, :attr:`y`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n Here, :attr:`x` and :attr:`y`, correspond to a local coordinate system\n where the local ``z`` axis is defined by :attr:`proj_axis`: which is the axis normal to this monitor.\n\n **Far-Field Approximation Selection**\n\n If the distance between the near and far field locations is much larger than the size of the\n device, one can typically set :attr:`far_field_approx` to ``True``, which will make use of the\n far-field approximation to speed up calculations. If the projection distance is comparable\n to the size of the device, we recommend setting :attr:`far_field_approx` to ``False``,\n so that the approximations are not used, and the projection is accurate even just a few\n wavelengths away from the near field locations.\n\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO unsure if add on params?\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter ``far_field_approx=False`` in the\n ``FieldProjectionCartesianMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include this example\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a DiffractionMonitor.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionCartesianMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... x=[-1, 0, 1],\n... y=[-2, -1, 0, 1, 2],\n... proj_axis=2,\n... proj_distance=5,\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", "type": "object", "properties": { "attrs": { @@ -14608,6 +14886,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -14726,7 +15007,7 @@ }, "FieldProjectionKSpaceMonitor": { "title": "FieldProjectionKSpaceMonitor", - "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on an observation plane defined in k-space.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\nux : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local x component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\nuy : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local y component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\n\n Notes\n -----\n\n The :attr:`center` and :attr:`size`\n fields define where the monitor will be placed in order to record near fields, typically\n very close to the structure of interest. The near fields are then\n projected to far-field locations defined in k-space by ``ux``, ``uy``, and ``proj_distance``,\n relative to the ``custom_origin``. Here, ``ux`` and ``uy`` are associated with a local\n coordinate system where the local 'z' axis is defined by ``proj_axis``: which is the axis\n normal to this monitor. If the distance between the near and far field locations is much\n larger than the size of the device, one can typically set ``far_field_approx`` to ``True``,\n which will make use of the far-field approximation to speed up calculations. If the\n projection distance is comparable to the size of the device, we recommend setting\n ``far_field_approx`` to ``False``, so that the approximations are not used, and the\n projection is accurate even just a few wavelengths away from the near field locations.\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a :class:`DiffractionMonitor`.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionKSpaceMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... proj_axis=2,\n... ux=[0.1,0.2],\n... uy=[0.3,0.4,0.5]\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on an observation plane defined in k-space.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\nux : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local x component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\nuy : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local y component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\n\n Notes\n -----\n\n The :attr:`center` and :attr:`size`\n fields define where the monitor will be placed in order to record near fields, typically\n very close to the structure of interest. The near fields are then\n projected to far-field locations defined in k-space by ``ux``, ``uy``, and ``proj_distance``,\n relative to the ``custom_origin``. Here, ``ux`` and ``uy`` are associated with a local\n coordinate system where the local 'z' axis is defined by ``proj_axis``: which is the axis\n normal to this monitor. If the distance between the near and far field locations is much\n larger than the size of the device, one can typically set ``far_field_approx`` to ``True``,\n which will make use of the far-field approximation to speed up calculations. If the\n projection distance is comparable to the size of the device, we recommend setting\n ``far_field_approx`` to ``False``, so that the approximations are not used, and the\n projection is accurate even just a few wavelengths away from the near field locations.\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a :class:`DiffractionMonitor`.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionKSpaceMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... proj_axis=2,\n... ux=[0.1,0.2],\n... uy=[0.3,0.4,0.5]\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", "type": "object", "properties": { "attrs": { @@ -15010,6 +15291,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -15126,7 +15410,7 @@ }, "DiffractionMonitor": { "title": "DiffractionMonitor", - "description": ":class:`Monitor` that uses a 2D Fourier transform to compute the\ndiffraction amplitudes and efficiency for allowed diffraction orders.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[False] = False\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Literal['+', '-'] = +\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Defaults to ``'+'`` if not provided.\n\nExample\n-------\n>>> monitor = DiffractionMonitor(\n... center=(1,2,3),\n... size=(inf,inf,0),\n... freqs=[250e12, 300e12],\n... name='diffraction_monitor',\n... normal_dir='+',\n... )\n\nSee Also\n--------\n\n**Notebooks**\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "description": ":class:`Monitor` that uses a 2D Fourier transform to compute the\ndiffraction amplitudes and efficiency for allowed diffraction orders.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[False] = False\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Literal['+', '-'] = +\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Defaults to ``'+'`` if not provided.\n\nExample\n-------\n>>> monitor = DiffractionMonitor(\n... center=(1,2,3),\n... size=(inf,inf,0),\n... freqs=[250e12, 300e12],\n... name='diffraction_monitor',\n... normal_dir='+',\n... )\n\nSee Also\n--------\n\n**Notebooks**\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", "type": "object", "properties": { "attrs": { @@ -15352,7 +15636,7 @@ }, "DirectivityMonitor": { "title": "DirectivityMonitor", - "description": ":class:`Monitor` that records the radiation characteristics of antennas in the frequency domain\nat specified observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[Tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNote\n----\nFor directivity, the computation is based on the ratio of the radiation\nintensity in a given direction to the average radiation intensity\nover all directions:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.6 (2016).\n\nFor axial ratio, the computation is based on:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.12 (2016).", + "description": ":class:`Monitor` that records the radiation characteristics of antennas in the frequency domain\nat specified observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNote\n----\nFor directivity, the computation is based on the ratio of the radiation\nintensity in a given direction to the average radiation intensity\nover all directions:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.6 (2016).\n\nFor axial ratio, the computation is based on:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.12 (2016).", "type": "object", "properties": { "attrs": { @@ -15636,6 +15920,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -15993,7 +16280,7 @@ }, "MeshOverrideStructure": { "title": "MeshOverrideStructure", - "description": "Defines an object that is only used in the process of generating the mesh.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\ndl : Tuple[PositiveFloat, PositiveFloat, PositiveFloat]\n [units = um]. Grid size along x, y, z directions.\nenforce : bool = False\n If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.\nshadow : bool = True\n In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.\ndrop_outside_sim : bool = True\n If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.\n\nNotes\n-----\n\n A :class:`MeshOverrideStructure` is a combination of geometry :class:`Geometry`,\n grid size along ``x``, ``y``, ``z`` directions, and a boolean on whether the override\n will be enforced.\n\nExample\n-------\n>>> from tidy3d import Box\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box')", + "description": "Defines an object that is only used in the process of generating the mesh.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : int = 0\n Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.\ndl : Tuple[PositiveFloat, PositiveFloat, PositiveFloat]\n [units = um]. Grid size along x, y, z directions.\nenforce : bool = False\n If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.\nshadow : bool = True\n In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.\ndrop_outside_sim : bool = True\n If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.\n\nNotes\n-----\n\n A :class:`MeshOverrideStructure` is a combination of geometry :class:`Geometry`,\n grid size along ``x``, ``y``, ``z`` directions, and a boolean on whether the override\n will be enforced.\n\nExample\n-------\n>>> from tidy3d import Box\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box')", "type": "object", "properties": { "attrs": { @@ -16076,6 +16363,9 @@ { "$ref": "#/definitions/PECMedium" }, + { + "$ref": "#/definitions/PMCMedium" + }, { "$ref": "#/definitions/PoleResidue" }, @@ -16153,6 +16443,12 @@ } ] }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.", + "default": 0, + "type": "integer" + }, "type": { "title": "Type", "default": "MeshOverrideStructure", @@ -16252,7 +16548,7 @@ }, "CornerFinderSpec": { "title": "CornerFinderSpec", - "description": "Specification for corner detection on a 2D plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmedium : Literal['metal', 'dielectric', 'all'] = metal\n Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.\nangle_threshold : ConstrainedFloatValue = 0.3141592653589793\n A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.\ndistance_threshold : Optional[PositiveFloat] = None\n If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.", + "description": "Specification for corner detection on a 2D plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmedium : Literal['metal', 'dielectric', 'all'] = metal\n Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.\nangle_threshold : ConstrainedFloatValue = 0.3141592653589793\n A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.\ndistance_threshold : Optional[PositiveFloat] = None\n If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.\nconcave_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nconvex_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nmixed_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", "type": "object", "properties": { "attrs": { @@ -16286,6 +16582,24 @@ "exclusiveMinimum": 0, "type": "number" }, + "concave_resolution": { + "title": "Concave Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "convex_resolution": { + "title": "Convex Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mixed_resolution": { + "title": "Mixed Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, "type": { "title": "Type", "default": "CornerFinderSpec", @@ -16299,7 +16613,7 @@ }, "LayerRefinementSpec": { "title": "LayerRefinementSpec", - "description": "Specification for automatic mesh refinement and snapping in layered structures. Structure corners\non the cross section perpendicular to layer thickness direction can be automatically identified. Subsequently,\nmesh is snapped and refined around the corners. Mesh can also be refined and snapped around the bounds along\nthe layer thickness direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\naxis : Literal[0, 1, 2]\n Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).\nmin_steps_along_axis : Optional[PositiveFloat] = None\n If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.\nbounds_refinement : Optional[GridRefinement] = None\n If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.\nbounds_snapping : Optional[Literal['bounds', 'lower', 'upper', 'center']] = lower\n If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.\ncorner_finder : Optional[CornerFinderSpec] = CornerFinderSpec(attrs={}, medium='metal', angle_threshold=0.3141592653589793, distance_threshold=None, type='CornerFinderSpec')\n Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.\ncorner_snapping : bool = True\n If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.\ncorner_refinement : Optional[GridRefinement] = GridRefinement(attrs={}, refinement_factor=None, dl=None, num_cells=3, type='GridRefinement')\n If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. \nrefinement_inside_sim_only : bool = True\n If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.\n\nNote\n----\n\nCorner detection is performed on a 2D plane sitting in the middle of the layer. If the layer is finite\nalong inplane axes, corners outside the bounds are discarded.\n\nNote\n----\n\nThis class only takes effect when :class:`AutoGrid` is applied.\n\nExample\n-------\n>>> layer_spec = LayerRefinementSpec(axis=2, center=(0,0,0), size=(2, 3, 1))", + "description": "Specification for automatic mesh refinement and snapping in layered structures. Structure corners\non the cross section perpendicular to layer thickness direction can be automatically identified. Subsequently,\nmesh is snapped and refined around the corners. Mesh can also be refined and snapped around the bounds along\nthe layer thickness direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\naxis : Literal[0, 1, 2]\n Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).\nmin_steps_along_axis : Optional[PositiveFloat] = None\n If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.\nbounds_refinement : Optional[GridRefinement] = None\n If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.\nbounds_snapping : Optional[Literal['bounds', 'lower', 'upper', 'center']] = lower\n If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.\ncorner_finder : Optional[CornerFinderSpec] = CornerFinderSpec(attrs={}, medium='metal', angle_threshold=0.3141592653589793, distance_threshold=None, concave_resolution=None, convex_resolution=None, mixed_resolution=None, type='CornerFinderSpec')\n Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.\ncorner_snapping : bool = True\n If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.\ncorner_refinement : Optional[GridRefinement] = GridRefinement(attrs={}, refinement_factor=None, dl=None, num_cells=3, type='GridRefinement')\n If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. \nrefinement_inside_sim_only : bool = True\n If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.\ngap_meshing_iters : NonNegativeInt = 1\n Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.\ndl_min_from_gap_width : bool = True\n Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.\n\nNote\n----\n\nCorner detection is performed on a 2D plane sitting in the middle of the layer. If the layer is finite\nalong inplane axes, corners outside the bounds are discarded.\n\nNote\n----\n\nThis class only takes effect when :class:`AutoGrid` is applied.\n\nExample\n-------\n>>> layer_spec = LayerRefinementSpec(axis=2, center=(0,0,0), size=(2, 3, 1))", "type": "object", "properties": { "attrs": { @@ -16471,6 +16785,9 @@ "medium": "metal", "angle_threshold": 0.3141592653589793, "distance_threshold": null, + "concave_resolution": null, + "convex_resolution": null, + "mixed_resolution": null, "type": "CornerFinderSpec" }, "allOf": [ @@ -16506,6 +16823,19 @@ "description": "If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.", "default": true, "type": "boolean" + }, + "gap_meshing_iters": { + "title": "Gap Meshing Iterations", + "description": "Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "dl_min_from_gap_width": { + "title": "Set ``dl_min`` from Estimated Gap Width", + "description": "Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.", + "default": true, + "type": "boolean" } }, "required": [ @@ -16516,7 +16846,7 @@ }, "GridSpec": { "title": "GridSpec", - "description": "Collective grid specification for all three dimensions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngrid_x : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along x-axis\ngrid_y : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along y-axis\ngrid_z : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along z-axis\nwavelength : Optional[float] = None\n [units = um]. Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.\noverride_structures : Tuple[Annotated[Union[tidy3d.components.structure.Structure, tidy3d.components.structure.MeshOverrideStructure], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nsnapping_points : Tuple[Tuple[Optional[float], Optional[float], Optional[float]], ...] = ()\n A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nlayer_refinement_specs : Tuple[LayerRefinementSpec, ...] = ()\n Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.\n\nExample\n-------\n>>> uniform = UniformGrid(dl=0.1)\n>>> custom = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])\n>>> auto = AutoGrid(min_steps_per_wvl=12)\n>>> grid_spec = GridSpec(grid_x=uniform, grid_y=custom, grid_z=auto, wavelength=1.5)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "description": "Collective grid specification for all three dimensions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngrid_x : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along x-axis\ngrid_y : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along y-axis\ngrid_z : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along z-axis\nwavelength : Optional[float] = None\n [units = um]. Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.\noverride_structures : Tuple[Annotated[Union[tidy3d.components.structure.Structure, tidy3d.components.structure.MeshOverrideStructure], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nsnapping_points : Tuple[tuple[Optional[float], Optional[float], Optional[float]], ...] = ()\n A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nlayer_refinement_specs : Tuple[LayerRefinementSpec, ...] = ()\n Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.\n\nExample\n-------\n>>> uniform = UniformGrid(dl=0.1)\n>>> custom = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])\n>>> auto = AutoGrid(min_steps_per_wvl=12)\n>>> grid_spec = GridSpec(grid_x=uniform, grid_y=custom, grid_z=auto, wavelength=1.5)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", "type": "object", "properties": { "attrs": { @@ -17010,7 +17340,7 @@ }, "RLCNetwork": { "title": "RLCNetwork", - "description": "Class for representing a simple network consisting of a resistor, capacitor, and inductor.\nProvides additional functionality for representing the network as an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nresistance : Optional[PositiveFloat] = None\n Resistance value in ohms.\ncapacitance : Optional[PositiveFloat] = None\n Capacitance value in farads.\ninductance : Optional[PositiveFloat] = None\n Inductance value in henrys.\nnetwork_topology : Literal['series', 'parallel'] = series\n Describes whether network elements are connected in ``series`` or ``parallel``.\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... )", + "description": "Class for representing a simple network consisting of a resistor, capacitor, and inductor.\nProvides additional functionality for representing the network as an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nresistance : Optional[PositiveFloat] = None\n Resistance value in ohms.\ncapacitance : Optional[PositiveFloat] = None\n Capacitance value in farads.\ninductance : Optional[PositiveFloat] = None\n Inductance value in henrys.\nnetwork_topology : Literal['series', 'parallel'] = series\n Describes whether network elements are connected in ``series`` or ``parallel``.\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP", "type": "object", "properties": { "attrs": { @@ -17063,7 +17393,7 @@ }, "AdmittanceNetwork": { "title": "AdmittanceNetwork", - "description": "Class for representing a network consisting of an arbitrary number of resistors,\ncapacitors, and inductors. The network is represented in the Laplace domain\nas an admittance function. Provides additional functionality for representing the network\nas an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\na : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.\nb : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.\n\nNotes\n-----\n\n The network is described by the supplied coefficients as an admittance function that relates\n voltage to the current in the Laplace domain and is equivalent to a frequency-dependent\n complex conductivity :math:`\\sigma(\\omega)`.\n\n .. math::\n I(s) = Y(s)V(s)\n\n .. math::\n Y(s) = \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}\n\n An equivalent :class:`.PoleResidue` medium is constructed using an equivalent frequency-dependent\n complex permittivity defined as\n\n .. math::\n \\epsilon(s) = \\epsilon_\\infty - \\frac{\\Delta}{\\epsilon_0 s}\n \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}.\n\n The admittance is scaled depending on the geometric properties of the lumped element by\n the scaling factor :math:`\\Delta`. Implementation is based on the equivalent medium introduced\n by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> R = 50\n>>> C = 1e-12\n>>> a = (1, R * C) # Coefficients for an RC parallel network\n>>> b = (R, 0)\n>>> RC_parallel = AdmittanceNetwork(a=a,\n... b=b\n... )", + "description": "Class for representing a network consisting of an arbitrary number of resistors,\ncapacitors, and inductors. The network is represented in the Laplace domain\nas an admittance function. Provides additional functionality for representing the network\nas an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\na : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.\nb : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.\n\nNotes\n-----\n\n The network is described by the supplied coefficients as an admittance function that relates\n voltage to the current in the Laplace domain and is equivalent to a frequency-dependent\n complex conductivity :math:`\\sigma(\\omega)`.\n\n .. math::\n I(s) = Y(s)V(s)\n\n .. math::\n Y(s) = \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}\n\n An equivalent :class:`.PoleResidue` medium is constructed using an equivalent frequency-dependent\n complex permittivity defined as\n\n .. math::\n \\epsilon(s) = \\epsilon_\\infty - \\frac{\\Delta}{\\epsilon_0 s}\n \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}.\n\n The admittance is scaled depending on the geometric properties of the lumped element by\n the scaling factor :math:`\\Delta`. Implementation is based on the equivalent medium introduced\n by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> R = 50\n>>> C = 1e-12\n>>> a = (1, R * C) # Coefficients for an RC parallel network\n>>> b = (R, 0)\n>>> RC_parallel = AdmittanceNetwork(a=a,\n... b=b\n... ) # doctest: +SKIP", "type": "object", "properties": { "attrs": { @@ -17107,7 +17437,7 @@ }, "LinearLumpedElement": { "title": "LinearLumpedElement", - "description": "Lumped element representing a network consisting of resistors, capacitors, and inductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nnetwork : Union[RLCNetwork, AdmittanceNetwork]\n The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Switches between the different methods for distributing the lumped element over the grid.\n\n\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... )\n>>> linear_element = LinearLumpedElement(\n... center=[0, 0, 0],\n... size=[2, 0, 3],\n... voltage_axis=0,\n... network=RL_series,\n... name=\"LumpedRL\"\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `Using lumped elements in Tidy3D simulations <../../notebooks/LinearLumpedElements.html>`_", + "description": "Lumped element representing a network consisting of resistors, capacitors, and inductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nnetwork : Union[RLCNetwork, AdmittanceNetwork]\n The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Switches between the different methods for distributing the lumped element over the grid.\n\n\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP\n>>> linear_element = LinearLumpedElement(\n... center=[0, 0, 0],\n... size=[2, 0, 3],\n... voltage_axis=0,\n... network=RL_series,\n... name=\"LumpedRL\"\n... ) # doctest: +SKIP\n\n\nSee Also\n--------\n\n**Notebooks:**\n * `Using lumped elements in Tidy3D simulations <../../notebooks/LinearLumpedElements.html>`_", "type": "object", "properties": { "attrs": { @@ -17426,7 +17756,7 @@ }, "PECConformal": { "title": "PECConformal", - "description": "Apply a subpixel averaging method known as conformal mesh scheme to PEC boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.3\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\n\nNote\n----\nThe algorithm is based on:\n\n S. Dey and R. Mittra, \"A locally conformal finite-difference\n time-domain (FDTD) algorithm for modeling three-dimensional\n perfectly conducting objects\",\n IEEE Microwave and Guided Wave Letters, 7(9), 273 (1997).\n\n S. Benkler, N. Chavannes and N. Kuster, \"A new 3-D conformal\n PEC FDTD scheme with user-defined geometric precision and derived\n stability criterion\",\n IEEE Transactions on Antennas and Propagation, 54(6), 1843 (2006).", + "description": "Apply a subpixel averaging method known as conformal mesh scheme to PEC boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.3\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.\n\nNote\n----\nThe algorithm is based on:\n\n S. Dey and R. Mittra, \"A locally conformal finite-difference\n time-domain (FDTD) algorithm for modeling three-dimensional\n perfectly conducting objects\",\n IEEE Microwave and Guided Wave Letters, 7(9), 273 (1997).\n\n S. Benkler, N. Chavannes and N. Kuster, \"A new 3-D conformal\n PEC FDTD scheme with user-defined geometric precision and derived\n stability criterion\",\n IEEE Transactions on Antennas and Propagation, 54(6), 1843 (2006).", "type": "object", "properties": { "attrs": { @@ -17450,13 +17780,19 @@ "exclusiveMaximum": 1, "minimum": 0, "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" } }, "additionalProperties": false }, "SurfaceImpedance": { "title": "SurfaceImpedance", - "description": "Apply 1st order (Leontovich) surface impedance boundary condition to\nstructure made of :class:`.LossyMetalMedium`.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.0\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "description": "Apply 1st order (Leontovich) surface impedance boundary condition to\nstructure made of :class:`.LossyMetalMedium`.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.0\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", "type": "object", "properties": { "attrs": { @@ -17480,13 +17816,19 @@ "exclusiveMaximum": 1, "minimum": 0, "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" } }, "additionalProperties": false }, "SubpixelSpec": { "title": "SubpixelSpec", - "description": "Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndielectric : Union[Staircasing, PolarizedAveraging, ContourPathAveraging] = PolarizedAveraging(attrs={}, type='PolarizedAveraging')\n Subpixel averaging method applied to dielectric material interfaces.\nmetal : Union[Staircasing, VolumetricAveraging] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.\npec : Union[Staircasing, HeuristicPECStaircasing, PECConformal] = PECConformal(attrs={}, type='PECConformal', timestep_reduction=0.3)\n Subpixel averaging method applied to PEC structure interfaces.\nlossy_metal : Union[Staircasing, VolumetricAveraging, SurfaceImpedance] = SurfaceImpedance(attrs={}, type='SurfaceImpedance', timestep_reduction=0.0)\n Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "description": "Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndielectric : Union[Staircasing, PolarizedAveraging, ContourPathAveraging] = PolarizedAveraging(attrs={}, type='PolarizedAveraging')\n Subpixel averaging method applied to dielectric material interfaces.\nmetal : Union[Staircasing, VolumetricAveraging] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.\npec : Union[Staircasing, HeuristicPECStaircasing, PECConformal] = PECConformal(attrs={}, type='PECConformal', timestep_reduction=0.3, edge_singularity_correction=False)\n Subpixel averaging method applied to PEC structure interfaces.\npmc : Union[Staircasing, HeuristicPECStaircasing] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to PMC structure interfaces.\nlossy_metal : Union[Staircasing, VolumetricAveraging, SurfaceImpedance] = SurfaceImpedance(attrs={}, type='SurfaceImpedance', timestep_reduction=0.0, edge_singularity_correction=False)\n Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", "type": "object", "properties": { "attrs": { @@ -17551,7 +17893,8 @@ "default": { "attrs": {}, "type": "PECConformal", - "timestep_reduction": 0.3 + "timestep_reduction": 0.3, + "edge_singularity_correction": false }, "discriminator": { "propertyName": "type", @@ -17573,13 +17916,37 @@ } ] }, + "pmc": { + "title": "Subpixel Averaging Method For PMC Interfaces", + "description": "Subpixel averaging method applied to PMC structure interfaces.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + } + ] + }, "lossy_metal": { "title": "Subpixel Averaging Method for Lossy Metal Interfaces", "description": "Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", "default": { "attrs": {}, "type": "SurfaceImpedance", - "timestep_reduction": 0.0 + "timestep_reduction": 0.0, + "edge_singularity_correction": false }, "discriminator": { "propertyName": "type", diff --git a/schemas/TerminalComponentModeler.json b/schemas/TerminalComponentModeler.json new file mode 100644 index 0000000000..defdc67cd3 --- /dev/null +++ b/schemas/TerminalComponentModeler.json @@ -0,0 +1,25583 @@ +{ + "title": "TerminalComponentModeler", + "description": "Tool for modeling two-terminal multiport devices and computing port parameters\nwith lumped and wave ports.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsimulation : Simulation\n Simulation describing the device without any sources present.\nports : Tuple[Union[LumpedPort, CoaxialLumpedPort, WavePort], ...] = ()\n Collection of lumped and wave ports associated with the network. For each port, one simulation will be run with a source that is associated with the port.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies at which to compute port parameters.\nremove_dc_component : bool = True\n Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.\nfolder_name : str = default\n Name of the folder for the tasks on web.\nverbose : bool = False\n Whether the :class:`.AbstractComponentModeler` should print status and progressbars.\ncallback_url : Optional[str] = None\n Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.\npath_dir : str = .\n Base directory where data and batch will be downloaded.\nsolver_version : Optional[str] = None\n batch_cached : Optional[Batch] = None\n Optional field to specify ``batch``. Only used as a workaround internally so that ``batch`` is written when ``.to_file()`` and then the proper batch is loaded from ``.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.\nradiation_monitors : Tuple[DirectivityMonitor, ...] = ()\n Facilitates the calculation of figures-of-merit for antennas. These monitor will be included in every simulation and record the radiated fields. ", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "simulation": { + "title": "Simulation", + "description": "Simulation describing the device without any sources present.", + "allOf": [ + { + "$ref": "#/definitions/Simulation" + } + ] + }, + "ports": { + "title": "Terminal Ports", + "description": "Collection of lumped and wave ports associated with the network. For each port, one simulation will be run with a source that is associated with the port.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/LumpedPort" + }, + { + "$ref": "#/definitions/CoaxialLumpedPort" + }, + { + "$ref": "#/definitions/WavePort" + } + ] + } + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies at which to compute port parameters.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "remove_dc_component": { + "title": "Remove DC Component", + "description": "Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.", + "default": true, + "type": "boolean" + }, + "folder_name": { + "title": "Folder Name", + "description": "Name of the folder for the tasks on web.", + "default": "default", + "type": "string" + }, + "verbose": { + "title": "Verbosity", + "description": "Whether the :class:`.AbstractComponentModeler` should print status and progressbars.", + "default": false, + "type": "boolean" + }, + "callback_url": { + "title": "Callback URL", + "description": "Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.", + "type": "string" + }, + "path_dir": { + "title": "Directory Path", + "description": "Base directory where data and batch will be downloaded.", + "default": ".", + "type": "string" + }, + "solver_version": { + "title": "Solver Version", + "description_str": "Custom solver version to use. If not supplied, uses default for the current front end version.", + "type": "string" + }, + "batch_cached": { + "title": "Batch (Cached)", + "description": "Optional field to specify ``batch``. Only used as a workaround internally so that ``batch`` is written when ``.to_file()`` and then the proper batch is loaded from ``.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.", + "allOf": [ + { + "$ref": "#/definitions/Batch" + } + ] + }, + "type": { + "title": "Type", + "default": "TerminalComponentModeler", + "enum": [ + "TerminalComponentModeler" + ], + "type": "string" + }, + "radiation_monitors": { + "title": "Radiation Monitors", + "description": "Facilitates the calculation of figures-of-merit for antennas. These monitor will be included in every simulation and record the radiated fields. ", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/DirectivityMonitor" + } + } + }, + "required": [ + "simulation", + "freqs" + ], + "additionalProperties": false, + "definitions": { + "NonlinearSusceptibility": { + "title": "NonlinearSusceptibility", + "description": "Model for an instantaneous nonlinear chi3 susceptibility.\nThe expression for the instantaneous nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nchi3 : float = 0\n [units = um^2 / V^2]. Chi3 nonlinear susceptibility.\nnumiters : Optional[PositiveInt] = None\n Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\chi_3` must be real.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "NonlinearSusceptibility", + "enum": [ + "NonlinearSusceptibility" + ], + "type": "string" + }, + "chi3": { + "title": "Chi3", + "description": "Chi3 nonlinear susceptibility.", + "default": 0, + "units": "um^2 / V^2", + "type": "number" + }, + "numiters": { + "title": "Number of iterations", + "description": "Deprecated. The old usage 'nonlinear_spec=model' with 'model.numiters' is deprecated and will be removed in a future release. The new usage is 'nonlinear_spec=NonlinearSpec(models=\\[model], num_iters=num_iters)'. Under the new usage, this parameter is ignored, and 'NonlinearSpec.num_iters' is used instead.", + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "additionalProperties": false + }, + "ComplexNumber": { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + "TwoPhotonAbsorption": { + "title": "TwoPhotonAbsorption", + "description": "Model for two-photon absorption (TPA) nonlinearity which gives an intensity-dependent\nabsorption of the form :math:`\\alpha = \\alpha_0 + \\beta I`.\nAlso includes free-carrier absorption (FCA) and free-carrier plasma dispersion (FCPD) effects.\nThe expression for the nonlinear polarization is given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nbeta : Union[float, tidycomplex, ComplexNumber] = 0\n [units = um / W]. Coefficient for two-photon absorption (TPA).\ntau : NonNegativeFloat = 0\n [units = sec]. Lifetime for the free carriers created by two-photon absorption (TPA).\nsigma : NonNegativeFloat = 0\n [units = um^2]. Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.\ne_e : NonNegativeFloat = 1\n Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\ne_h : NonNegativeFloat = 1\n Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_e : float = 0\n [units = um^(3 e_e)]. Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).\nc_h : float = 0\n [units = um^(3 e_h)]. Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\nfreq0 : Optional[PositiveFloat] = None\n Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\beta` must be real.\n\n .. math::\n\n P_{NL} = P_{TPA} + P_{FCA} + P_{FCPD} \\\\\n P_{TPA} = -\\frac{4}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{2 i \\omega} |E|^2 E \\\\\n P_{FCA} = -\\frac{c_0 \\varepsilon_0 n_0 \\sigma N_f}{i \\omega} E \\\\\n \\frac{dN_f}{dt} = \\frac{8}{3}\\frac{c_0^2 \\varepsilon_0^2 n_0^2 \\beta}{8 q_e \\hbar \\omega} |E|^4 - \\frac{N_f}{\\tau} \\\\\n N_e = N_h = N_f \\\\\n P_{FCPD} = \\varepsilon_0 2 n_0 \\Delta n (N_f) E \\\\\n \\Delta n (N_f) = (c_e N_e^{e_e} + c_h N_h^{e_h})\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n The implementation is described in::\n\n N. Suzuki, \"FDTD Analysis of Two-Photon Absorption and Free-Carrier Absorption in Si\n High-Index-Contrast Waveguides,\" J. Light. Technol. 25, 9 (2007).\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> tpa_model = TwoPhotonAbsorption(beta=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TwoPhotonAbsorption", + "enum": [ + "TwoPhotonAbsorption" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "beta": { + "title": "TPA coefficient", + "description": "Coefficient for two-photon absorption (TPA).", + "default": 0, + "units": "um / W", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "tau": { + "title": "Carrier lifetime", + "description": "Lifetime for the free carriers created by two-photon absorption (TPA).", + "default": 0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "sigma": { + "title": "FCA cross section", + "description": "Total cross section for free-carrier absorption (FCA). Contains contributions from electrons and from holes.", + "default": 0, + "units": "um^2", + "minimum": 0, + "type": "number" + }, + "e_e": { + "title": "Electron exponent", + "description": "Exponent for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "e_h": { + "title": "Hole exponent", + "description": "Exponent for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 1, + "minimum": 0, + "type": "number" + }, + "c_e": { + "title": "Electron coefficient", + "description": "Coefficient for the free electron refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_e)", + "type": "number" + }, + "c_h": { + "title": "Hole coefficient", + "description": "Coefficient for the free hole refractive index shift in the free-carrier plasma dispersion (FCPD).", + "default": 0, + "units": "um^(3 e_h)", + "type": "number" + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "freq0": { + "title": "Central frequency", + "description": "Central frequency, used to calculate the energy of the free-carriers excited by two-photon absorption. If not provided, it is obtained automatically from the simulation sources (as long as these are all equal).", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "KerrNonlinearity": { + "title": "KerrNonlinearity", + "description": "Model for Kerr nonlinearity which gives an intensity-dependent refractive index\nof the form :math:`n = n_0 + n_2 I`. The expression for the nonlinear polarization\nis given below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nuse_complex_fields : bool = False\n Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.\nn2 : Union[tidycomplex, ComplexNumber] = 0\n [units = um^2 / W]. Nonlinear refractive index in the Kerr nonlinearity.\nn0 : Union[tidycomplex, ComplexNumber, NoneType] = None\n Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).\n\nNotes\n-----\n\n This model uses real time-domain fields, so :math:`\\n_2` must be real.\n\n This model is equivalent to a :class:`.NonlinearSusceptibility`; the\n relation between the parameters is given below.\n\n .. math::\n\n P_{NL} = \\varepsilon_0 \\chi_3 |E|^2 E \\\\\n n_2 = \\frac{3}{4 n_0^2 \\varepsilon_0 c_0} \\chi_3\n\n In these equations, :math:`n_0` means the real part of the linear\n refractive index of the medium.\n\n To simulate nonlinear loss, consider instead using a :class:`.TwoPhotonAbsorption`\n model, which implements a more physical dispersive loss of the form\n :math:`\\chi_{TPA} = i \\frac{c_0 n_0 \\beta}{\\omega} I`.\n\n The nonlinear constitutive relation is solved iteratively; it may not converge\n for strong nonlinearities. Increasing :attr:`tidy3d.NonlinearSpec.num_iters` can\n help with convergence.\n\n For complex fields (e.g. when using Bloch boundary conditions), the nonlinearity\n is applied separately to the real and imaginary parts, so that the above equation\n holds when both :math:`E` and :math:`P_{NL}` are replaced by their real or imaginary parts.\n The nonlinearity is only applied to the real-valued fields since they are the\n physical fields.\n\n Different field components do not interact nonlinearly. For example,\n when calculating :math:`P_{NL, x}`, we approximate :math:`|E|^2 \\approx |E_x|^2`.\n This approximation is valid when the :math:`E` field is predominantly polarized along one\n of the ``x``, ``y``, or ``z`` axes.\n\n .. TODO add links to notebooks here.\n\nExample\n-------\n>>> kerr_model = KerrNonlinearity(n2=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "KerrNonlinearity", + "enum": [ + "KerrNonlinearity" + ], + "type": "string" + }, + "use_complex_fields": { + "title": "Use complex fields", + "description": "Whether to use the old deprecated complex-fields implementation. The default real-field implementation is more physical and is always recommended; this option is only available for backwards compatibility with Tidy3D version < 2.8 and may be removed in a future release.", + "default": false, + "type": "boolean" + }, + "n2": { + "title": "Nonlinear refractive index", + "description": "Nonlinear refractive index in the Kerr nonlinearity.", + "default": 0, + "units": "um^2 / W", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "n0": { + "title": "Complex linear refractive index", + "description": "Complex linear refractive index of the medium, computed for instance using 'medium.nk_model'. If not provided, it is calculated automatically using the central frequencies of the simulation sources (as long as these are all equal).", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "additionalProperties": false + }, + "NonlinearSpec": { + "title": "NonlinearSpec", + "description": "Abstract specification for adding nonlinearities to a medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmodels : Tuple[Union[NonlinearSusceptibility, TwoPhotonAbsorption, KerrNonlinearity], ...] = ()\n The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.\nnum_iters : PositiveInt = 5\n Number of iterations for solving nonlinear constitutive relation.\n\nNote\n----\nThe nonlinear constitutive relation is solved iteratively; it may not converge\nfor strong nonlinearities. Increasing ``num_iters`` can help with convergence.\n\nExample\n-------\n>>> nonlinear_susceptibility = NonlinearSusceptibility(chi3=1)\n>>> nonlinear_spec = NonlinearSpec(models=[nonlinear_susceptibility])\n>>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "models": { + "title": "Nonlinear models", + "description": "The nonlinear models present in this nonlinear spec. Nonlinear models of different types are additive. Multiple nonlinear models of the same type are not allowed.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSusceptibility" + }, + { + "$ref": "#/definitions/TwoPhotonAbsorption" + }, + { + "$ref": "#/definitions/KerrNonlinearity" + } + ] + } + }, + "num_iters": { + "title": "Number of iterations", + "description": "Number of iterations for solving nonlinear constitutive relation.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "NonlinearSpec", + "enum": [ + "NonlinearSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SpaceModulation": { + "title": "SpaceModulation", + "description": "The modulation profile with a user-supplied spatial distribution of\namplitude and phase.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : Union[float, SpatialDataArray] = 1\n Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.\nphase : Union[float, SpatialDataArray] = 0\n [units = rad]. Phase of modulation that can vary spatially.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Method of interpolation to use to obtain values at spatial locations on the Yee grids.\n\nNote\n----\n.. math::\n\n amp\\_space(r) = amplitude(r) \\cdot e^{i \\cdot phase(r)}\n\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> amp = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> phase = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> space = SpaceModulation(amplitude=amp, phase=phase)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SpaceModulation", + "enum": [ + "SpaceModulation" + ], + "type": "string" + }, + "amplitude": { + "title": "Amplitude of modulation in space", + "description": "Amplitude of modulation that can vary spatially. It takes the unit of whatever is being modulated.", + "default": 1, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "phase": { + "title": "Phase of modulation in space", + "description": "Phase of modulation that can vary spatially.", + "default": 0, + "units": "rad", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Method of interpolation to use to obtain values at spatial locations on the Yee grids.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContinuousWaveTimeModulation": { + "title": "ContinuousWaveTimeModulation", + "description": "Class describing modulation with a harmonic time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Modulation frequency.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t}\n\nNote\n----\nThe full space-time modulation is,\n\n.. math::\n\n amp(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]\n\n\nExample\n-------\n>>> cw = ContinuousWaveTimeModulation(freq0=200e12, amplitude=1, phase=0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWaveTimeModulation", + "enum": [ + "ContinuousWaveTimeModulation" + ], + "type": "string" + }, + "freq0": { + "title": "Modulation Frequency", + "description": "Modulation frequency.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "freq0" + ], + "additionalProperties": false + }, + "SpaceTimeModulation": { + "title": "SpaceTimeModulation", + "description": "Space-time modulation applied to a medium, adding\non top of the time-independent part.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nspace_modulation : SpaceModulation = SpaceModulation(attrs={}, type='SpaceModulation', amplitude=1.0, phase=0.0, interp_method='nearest')\n Space modulation part from the separable SpaceTimeModulation.\ntime_modulation : ContinuousWaveTimeModulation\n Time modulation part from the separable SpaceTimeModulation.\n\n\nNote\n----\nThe space-time modulation must be separable in space and time.\ne.g. when applied to permittivity,\n\n.. math::\n\n \\delta \\epsilon(r, t) = \\Re[amp\\_time(t) \\cdot amp\\_space(r)]", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "space_modulation": { + "title": "Space modulation", + "description": "Space modulation part from the separable SpaceTimeModulation.", + "default": { + "attrs": {}, + "type": "SpaceModulation", + "amplitude": 1.0, + "phase": 0.0, + "interp_method": "nearest" + }, + "allOf": [ + { + "$ref": "#/definitions/SpaceModulation" + } + ] + }, + "time_modulation": { + "title": "Time modulation", + "description": "Time modulation part from the separable SpaceTimeModulation.", + "allOf": [ + { + "$ref": "#/definitions/ContinuousWaveTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "SpaceTimeModulation", + "enum": [ + "SpaceTimeModulation" + ], + "type": "string" + } + }, + "required": [ + "time_modulation" + ], + "additionalProperties": false + }, + "ModulationSpec": { + "title": "ModulationSpec", + "description": "Specification adding space-time modulation to the non-dispersive part of medium\nincluding relative permittivity at infinite frequency and electric conductivity.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npermittivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.\nconductivity : Optional[SpaceTimeModulation] = None\n Space-time modulation of electric conductivity applied on top of the base conductivity.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "permittivity": { + "title": "Space-time modulation of relative permittivity", + "description": "Space-time modulation of relative permittivity at infinite frequency applied on top of the base permittivity at infinite frequency.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "conductivity": { + "title": "Space-time modulation of conductivity", + "description": "Space-time modulation of electric conductivity applied on top of the base conductivity.", + "allOf": [ + { + "$ref": "#/definitions/SpaceTimeModulation" + } + ] + }, + "type": { + "title": "Type", + "default": "ModulationSpec", + "enum": [ + "ModulationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VisualizationSpec": { + "title": "VisualizationSpec", + "description": "Defines specification for visualization when used with plotting functions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfacecolor : str = \n Color applied to the faces in visualization.\nedgecolor : Optional[str] = \n Color applied to the edges in visualization.\nalpha : Optional[ConstrainedFloatValue] = 1.0\n Opacity/alpha value in plotting between 0 and 1.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "facecolor": { + "title": "Face color", + "description": "Color applied to the faces in visualization.", + "default": "", + "type": "string" + }, + "edgecolor": { + "title": "Edge color", + "description": "Color applied to the edges in visualization.", + "default": "", + "type": "string" + }, + "alpha": { + "title": "Opacity", + "description": "Opacity/alpha value in plotting between 0 and 1.", + "default": 1.0, + "minimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "VisualizationSpec", + "enum": [ + "VisualizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FluidSpec": { + "title": "FluidSpec", + "description": "Fluid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidSpec", + "enum": [ + "FluidSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "SolidSpec": { + "title": "SolidSpec", + "description": "Solid medium class for backwards compatibility\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidSpec", + "enum": [ + "SolidSpec" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "SolidMedium": { + "title": "SolidMedium", + "description": "Solid medium for heat simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\ncapacity : Optional[PositiveFloat] = None\n [units = J/(kg*K)]. Specific heat capacity in unit of J/(kg*K).\nconductivity : PositiveFloat\n [units = W/(um*K)]. Thermal conductivity of material in units of W/(um*K).\ndensity : Optional[PositiveFloat] = None\n [units = kg/um^3]. Mass density of material in units of kg/um^3.\n\nExample\n-------\n>>> solid = SolidMedium(\n... capacity=2,\n... conductivity=3,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "SolidMedium", + "enum": [ + "SolidMedium" + ], + "type": "string" + }, + "capacity": { + "title": "Heat capacity", + "description": "Specific heat capacity in unit of J/(kg*K).", + "units": "J/(kg*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "conductivity": { + "title": "Thermal conductivity", + "description": "Thermal conductivity of material in units of W/(um*K).", + "units": "W/(um*K)", + "exclusiveMinimum": 0, + "type": "number" + }, + "density": { + "title": "Density", + "description": "Mass density of material in units of kg/um^3.", + "units": "kg/um^3", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "FluidMedium": { + "title": "FluidMedium", + "description": "Fluid medium. Heat simulations will not solve for temperature\nin a structure that has a medium with this 'heat_spec'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\n\nExample\n-------\n>>> solid = FluidMedium()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "FluidMedium", + "enum": [ + "FluidMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Medium": { + "title": "Medium", + "description": "Dispersionless medium. Mediums define the optical properties of the materials within the simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n In a dispersion-less medium, the displacement field :math:`D(t)` reacts instantaneously to the applied\n electric field :math:`E(t)`.\n\n .. math::\n\n D(t) = \\epsilon E(t)\n\nExample\n-------\n>>> dielectric = Medium(permittivity=4.0, name='my_medium')\n>>> eps = dielectric.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Introduction on Tidy3D working principles <../../notebooks/Primer.html#Mediums>`_\n * `Index <../../notebooks/docs/features/medium.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_\n\n**GUI**\n * `Mediums `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium", + "enum": [ + "Medium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "additionalProperties": false + }, + "HammerstadSurfaceRoughness": { + "title": "HammerstadSurfaceRoughness", + "description": "Modified Hammerstad surface roughness model. It's a popular model that works well\nunder 5 GHz for surface roughness below 2 micrometer RMS.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrq : PositiveFloat\n [units = um]. RMS peak-to-valley height (Rq) of the surface roughness.\nroughness_factor : ConstrainedFloatValue = 2.0\n Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n 1 + (RF-1) \\frac{2}{\\pi}\\arctan(1.4\\frac{R_q^2}{\\delta^2})\n\n where :math:`\\delta` is skin depth, :math:`R_q` the RMS peak-to-vally height, and RF\n roughness factor.\n\nNote\n----\nThis model is based on:\n\n Y. Shlepnev, C. Nwachukwu, \"Roughness characterization for interconnect analysis\",\n 2011 IEEE International Symposium on Electromagnetic Compatibility,\n (DOI: 10.1109/ISEMC.2011.6038367), 2011.\n\n V. Dmitriev-Zdorov, B. Simonovich, I. Kochikov, \"A Causal Conductor Roughness Model\n and its Effect on Transmission Line Characteristics\", Signal Integrity Journal, 2018.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HammerstadSurfaceRoughness", + "enum": [ + "HammerstadSurfaceRoughness" + ], + "type": "string" + }, + "rq": { + "title": "RMS Peak-to-Valley Height", + "description": "RMS peak-to-valley height (Rq) of the surface roughness.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "roughness_factor": { + "title": "Roughness Factor", + "description": "Expected maximal increase in conductor losses due to roughness effect. Value 2 gives the classic Hammerstad equation.", + "default": 2.0, + "exclusiveMinimum": 1.0, + "type": "number" + } + }, + "required": [ + "rq" + ], + "additionalProperties": false + }, + "HuraySurfaceRoughness": { + "title": "HuraySurfaceRoughness", + "description": "Huray surface roughness model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_area : PositiveFloat = 1\n Relative area of the matte base compared to a flat surface\ncoeffs : Tuple[tuple[pydantic.v1.types.PositiveFloat, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um)]. List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.\n\nNote\n----\n\n The power loss compared to smooth surface is described by:\n\n .. math::\n\n \\frac{A_{matte}}{A_{flat}} + \\frac{3}{2}\\sum_i f_i/[1+\\frac{\\delta}{r_i}+\\frac{\\delta^2}{2r_i^2}]\n\n where :math:`\\delta` is skin depth, :math:`r_i` the radius of sphere,\n :math:`\\frac{A_{matte}}{A_{flat}}` the relative area of the matte compared to flat surface,\n and :math:`f_i=N_i4\\pi r_i^2/A_{flat}` the ratio of total sphere\n surface area (number of spheres :math:`N_i` times the individual sphere surface area)\n to the flat surface area.\n\nNote\n----\nThis model is based on:\n\n J. Eric Bracken, \"A Causal Huray Model for Surface Roughness\", DesignCon, 2012.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HuraySurfaceRoughness", + "enum": [ + "HuraySurfaceRoughness" + ], + "type": "string" + }, + "relative_area": { + "title": "Relative Area", + "description": "Relative area of the matte base compared to a flat surface", + "default": 1, + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients for surface ratio and sphere radius", + "description": "List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is the ratio of total sphere surface area to the flat surface area, and :math:`r_i` the radius of the sphere.", + "units": [ + null, + "um" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "SurfaceImpedanceFitterParam": { + "title": "SurfaceImpedanceFitterParam", + "description": "Advanced parameters for fitting surface impedance of a :class:`.LossyMetalMedium`.\nInternally, the quantity to be fitted is surface impedance divided by ``-1j * \\omega``.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_num_poles : PositiveInt = 5\n Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.\ntolerance_rms : NonNegativeFloat = 0.001\n Tolerance in fitting.\nfrequency_sampling_points : PositiveInt = 20\n Number of sampling frequencies used in fitting.\nlog_sampling : bool = True\n Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "max_num_poles": { + "title": "Maximal Number Of Poles", + "description": "Maximal number of poles in complex-conjugate pole residue model for fitting surface impedance.", + "default": 5, + "exclusiveMinimum": 0, + "type": "integer" + }, + "tolerance_rms": { + "title": "Tolerance In Fitting", + "description": "Tolerance in fitting.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "frequency_sampling_points": { + "title": "Number Of Sampling Frequencies", + "description": "Number of sampling frequencies used in fitting.", + "default": 20, + "exclusiveMinimum": 0, + "type": "integer" + }, + "log_sampling": { + "title": "Frequencies Sampling In Log Scale", + "description": "Whether to sample frequencies logarithmically (``True``), or linearly (``False``).", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedanceFitterParam", + "enum": [ + "SurfaceImpedanceFitterParam" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LossyMetalMedium": { + "title": "LossyMetalMedium", + "description": "Lossy metal that can be modeled with a surface impedance boundary condition (SIBC).\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Tuple[float, float]\n [units = (Hz, Hz)]. Frequency range of validity for the medium.\nallow_gain : Literal[False] = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Literal[1] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\nroughness : Union[HammerstadSurfaceRoughness, HuraySurfaceRoughness] = None\n Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.\nthickness : Optional[PositiveFloat] = None\n [units = um]. When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.\nfit_param : SurfaceImpedanceFitterParam = SurfaceImpedanceFitterParam(attrs={}, max_num_poles=5, tolerance_rms=0.001, frequency_sampling_points=20, log_sampling=True, type='SurfaceImpedanceFitterParam')\n Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.\n\nNotes\n-----\n\n SIBC is most accurate when the skin depth is much smaller than the structure feature size.\n If not the case, please use a regular medium instead, or set ``simulation.subpixel.lossy_metal``\n to ``td.VolumetricAveraging()`` or ``td.Staircasing()``.\n\nExample\n-------\n>>> lossy_metal = LossyMetalMedium(conductivity=10, frequency_range=(9e9, 10e9))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Frequency range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "LossyMetalMedium", + "enum": [ + "LossyMetalMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "enum": [ + 1 + ], + "type": "integer" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "roughness": { + "title": "Surface Roughness Model", + "description": "Surface roughness model that applies a frequency-dependent scaling factor to surface impedance.", + "discriminator": { + "propertyName": "type", + "mapping": { + "HammerstadSurfaceRoughness": "#/definitions/HammerstadSurfaceRoughness", + "HuraySurfaceRoughness": "#/definitions/HuraySurfaceRoughness" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HammerstadSurfaceRoughness" + }, + { + "$ref": "#/definitions/HuraySurfaceRoughness" + } + ] + }, + "thickness": { + "title": "Conductor Thickness", + "description": "When the thickness of the conductor is not much greater than skin depth, 1D transmission line model is applied to compute the surface impedance of the thin conductor.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "fit_param": { + "title": "Fitting Parameters For Surface Impedance", + "description": "Parameters for fitting surface impedance divided by (-1j * omega) over the frequency range using pole-residue pair model.", + "default": { + "attrs": {}, + "max_num_poles": 5, + "tolerance_rms": 0.001, + "frequency_sampling_points": 20, + "log_sampling": true, + "type": "SurfaceImpedanceFitterParam" + }, + "allOf": [ + { + "$ref": "#/definitions/SurfaceImpedanceFitterParam" + } + ] + } + }, + "required": [ + "frequency_range" + ], + "additionalProperties": false + }, + "PoleResidue": { + "title": "PoleResidue", + "description": "A dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> pole_res = PoleResidue(eps_inf=2.0, poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PoleResidue", + "enum": [ + "PoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + } + }, + "additionalProperties": false + }, + "Sellmeier": { + "title": "Sellmeier", + "description": "A dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\n For lossless, weakly dispersive materials, the best way to incorporate the dispersion without doing\n complicated fits and without slowing the simulation down significantly is to provide the value of the\n refractive index dispersion :math:`\\frac{dn}{d\\lambda}` in :meth:`tidy3d.Sellmeier.from_dispersion`. The\n value is assumed to be at the central frequency or wavelength (whichever is provided), and a one-pole model\n for the material is generated.\n\nExample\n-------\n>>> sellmeier_medium = Sellmeier(coeffs=[(1,2), (3,4)])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomSellmeier`\n A spatially varying dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Sellmeier", + "enum": [ + "Sellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Lorentz": { + "title": "Lorentz", + "description": "A dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, float, pydantic.v1.types.NonNegativeFloat], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> lorentz_medium = Lorentz(eps_inf=2.0, coeffs=[(1,2,3), (4,5,6)])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Lorentz", + "enum": [ + "Lorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number", + "minimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Debye": { + "title": "Debye", + "description": "A dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> debye_medium = Debye(eps_inf=2.0, coeffs=[(1,2),(3,4)])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDebye`\n A spatially varying dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Debye", + "enum": [ + "Debye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "Drude": { + "title": "Drude", + "description": "A dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : PositiveFloat = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[float, pydantic.v1.types.PositiveFloat], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomDrude`:\n A spatially varying dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Drude", + "enum": [ + "Drude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "exclusiveMinimum": 0, + "type": "number" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + } + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "PECMedium": { + "title": "PECMedium", + "description": "Perfect electrical conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PECs, must import ``tidy3d.PEC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PECMedium", + "enum": [ + "PECMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCMedium": { + "title": "PMCMedium", + "description": "Perfect magnetic conductor class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\n\nNote\n----\n\n To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "PMCMedium", + "enum": [ + "PMCMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AnisotropicMedium": { + "title": "AnisotropicMedium", + "description": "Diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> medium_xx = Medium(permittivity=4.0)\n>>> medium_yy = Medium(permittivity=4.1)\n>>> medium_zz = Medium(permittivity=3.9)\n>>> anisotropic_dielectric = AnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`FullyAnisotropicMedium`\n Fully anisotropic medium including all 9 components of the permittivity and conductivity tensors.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMedium", + "enum": [ + "AnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "FullyAnisotropicMedium": { + "title": "FullyAnisotropicMedium", + "description": "Fully anisotropic medium including all 9 components of the permittivity and conductivity\ntensors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]\n [units = None (relative permittivity)]. Relative permittivity tensor.\nconductivity : ArrayLike[dtype=float, ndim=2, shape=(3, 3)] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n [units = S/um]. Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nNotes\n-----\n\n Provided permittivity tensor and the symmetric part of the conductivity tensor must\n have coinciding main directions. A non-symmetric conductivity tensor can be used to model\n magneto-optic effects. Note that dispersive properties and subpixel averaging are currently not\n supported for fully anisotropic materials.\n\nNote\n----\n\n Simulations involving fully anisotropic materials are computationally more intensive, thus,\n they take longer time to complete. This increase strongly depends on the filling fraction of\n the simulation domain by fully anisotropic materials, varying approximately in the range from\n 1.5 to 5. The cost of running a simulation is adjusted correspondingly.\n\nExample\n-------\n>>> perm = [[2, 0, 0], [0, 1, 0], [0, 0, 3]]\n>>> cond = [[0.1, 0, 0], [0, 0, 0], [0, 0, 0]]\n>>> anisotropic_dielectric = FullyAnisotropicMedium(permittivity=perm, conductivity=cond)\n\nSee Also\n--------\n\n:class:`CustomAnisotropicMedium`\n Diagonally anisotropic medium with spatially varying permittivity in each component.\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "FullyAnisotropicMedium", + "enum": [ + "FullyAnisotropicMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity tensor.", + "default": [ + [ + 1, + 0, + 0 + ], + [ + 0, + 1, + 0 + ], + [ + 0, + 0, + 1 + ] + ], + "units": "None (relative permittivity)", + "type": "ArrayLike" + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity tensor. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": [ + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ], + [ + 0, + 0, + 0 + ] + ], + "units": "S/um", + "type": "ArrayLike" + } + }, + "additionalProperties": false + }, + "PermittivityDataset": { + "title": "PermittivityDataset", + "description": "Dataset storing the diagonal components of the permittivity tensor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\neps_xx : ScalarFieldDataArray\n Spatial distribution of the xx-component of the relative permittivity.\neps_yy : ScalarFieldDataArray\n Spatial distribution of the yy-component of the relative permittivity.\neps_zz : ScalarFieldDataArray\n Spatial distribution of the zz-component of the relative permittivity.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> sclr_fld = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = PermittivityDataset(eps_xx=sclr_fld, eps_yy=sclr_fld, eps_zz=sclr_fld)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityDataset", + "enum": [ + "PermittivityDataset" + ], + "type": "string" + }, + "eps_xx": { + "title": "DataArray", + "description": "Spatial distribution of the xx-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_yy": { + "title": "DataArray", + "description": "Spatial distribution of the yy-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "eps_zz": { + "title": "DataArray", + "description": "Spatial distribution of the zz-component of the relative permittivity.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "eps_xx", + "eps_yy", + "eps_zz" + ], + "additionalProperties": false + }, + "TriangularGridDataset": { + "title": "TriangularGridDataset", + "description": "Dataset for storing triangular grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\nnormal_axis : Literal[0, 1, 2]\n Orientation of the grid.\nnormal_pos : float\n Coordinate of the grid along the normal direction.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tri_grid_points = PointDataArray(\n... [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(2)),\n... )\n>>>\n>>> tri_grid_cells = CellDataArray(\n... [[0, 1, 2], [1, 2, 3]],\n... coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)),\n... )\n>>>\n>>> tri_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tri_grid = TriangularGridDataset(\n... normal_axis=1,\n... normal_pos=0,\n... points=tri_grid_points,\n... cells=tri_grid_cells,\n... values=tri_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangularGridDataset", + "enum": [ + "TriangularGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "normal_axis": { + "title": "Grid Axis", + "description": "Orientation of the grid.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "normal_pos": { + "title": "Position", + "description": "Coordinate of the grid along the normal direction.", + "type": "number" + } + }, + "required": [ + "points", + "values", + "cells", + "normal_axis", + "normal_pos" + ], + "additionalProperties": false + }, + "TetrahedralGridDataset": { + "title": "TetrahedralGridDataset", + "description": "Dataset for storing tetrahedral grid data. Data values are associated with the nodes of\nthe grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\npoints : PointDataArray\n Coordinates of points composing the unstructured grid.\nvalues : Union[IndexedDataArray, IndexedVoltageDataArray, IndexedTimeDataArray, IndexedFieldVoltageDataArray, PointDataArray]\n Values stored at the grid points.\ncells : CellDataArray\n Cells composing the unstructured grid specified as connections between grid points.\n\nNote\n----\nTo use full functionality of unstructured datasets one must install ``vtk`` package (``pip\ninstall tidy3d[vtk]`` or ``pip install vtk``). Otherwise the functionality of unstructured\ndatasets is limited to creation, writing to/loading from a file, and arithmetic manipulations.\n\nExample\n-------\n>>> tet_grid_points = PointDataArray(\n... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],\n... coords=dict(index=np.arange(4), axis=np.arange(3)),\n... )\n>>>\n>>> tet_grid_cells = CellDataArray(\n... [[0, 1, 2, 3]],\n... coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)),\n... )\n>>>\n>>> tet_grid_values = IndexedDataArray(\n... [1.0, 2.0, 3.0, 4.0], coords=dict(index=np.arange(4)),\n... )\n>>>\n>>> tet_grid = TetrahedralGridDataset(\n... points=tet_grid_points,\n... cells=tet_grid_cells,\n... values=tet_grid_values,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TetrahedralGridDataset", + "enum": [ + "TetrahedralGridDataset" + ], + "type": "string" + }, + "points": { + "title": "DataArray", + "description": "Coordinates of points composing the unstructured grid.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "values": { + "title": "Point Values", + "description": "Values stored at the grid points.", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "cells": { + "title": "DataArray", + "description": "Cells composing the unstructured grid specified as connections between grid points.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "points", + "values", + "cells" + ], + "additionalProperties": false + }, + "CustomMedium": { + "title": "CustomMedium", + "description": ":class:`.Medium` with user-supplied permittivity distribution.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\neps_dataset : Optional[PermittivityDataset] = None\n [To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.\npermittivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = None (relative permittivity)]. Spatial profile of relative permittivity.\nconductivity : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], NoneType] = None\n [units = S/um]. Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> X = np.linspace(-1, 1, Nx)\n>>> Y = np.linspace(-1, 1, Ny)\n>>> Z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=X, y=Y, z=Z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> dielectric = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> eps = dielectric.eps_model(200e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomMedium", + "enum": [ + "CustomMedium" + ], + "type": "string" + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + }, + "eps_dataset": { + "title": "Permittivity Dataset", + "description": "[To be deprecated] User-supplied dataset containing complex-valued permittivity as a function of space. Permittivity distribution over the Yee-grid will be interpolated based on ``interp_method``.", + "allOf": [ + { + "$ref": "#/definitions/PermittivityDataset" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Spatial profile of relative permittivity.", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Spatial profile Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "units": "S/um", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + }, + "additionalProperties": false + }, + "CustomPoleResidue": { + "title": "CustomPoleResidue", + "description": "A spatially varying dispersive medium described by the pole-residue pair model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n In this method, the frequency-dependent permittivity :math:`\\epsilon(\\omega)` is expressed as a sum of\n resonant material poles _`[1]`.\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\n For each of these resonant poles identified by the index :math:`i`, an auxiliary differential equation is\n used to relate the auxiliary current :math:`J_i(t)` to the applied electric field :math:`E(t)`.\n The sum of all these auxiliary current contributions describes the total dielectric response of the material.\n\n .. math::\n\n \\frac{d}{dt} J_i (t) - a_i J_i (t) = \\epsilon_0 c_i \\frac{d}{dt} E (t)\n\n Hence, the computational cost increases with the number of poles.\n\n **References**\n\n .. [1] M. Han, R.W. Dutton and S. Fan, IEEE Microwave and Wireless Component Letters, 16, 119 (2006).\n\n .. TODO add links to notebooks using this.\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> a1 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> a2 = SpatialDataArray(-np.random.random((5, 6, 7)), coords=coords)\n>>> c2 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> pole_res = CustomPoleResidue(eps_inf=eps_inf, poles=[(a1, c1), (a2, c2)])\n>>> eps = pole_res.eps_model(200e12)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n\n* `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomPoleResidue", + "enum": [ + "CustomPoleResidue" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf" + ], + "additionalProperties": false + }, + "CustomSellmeier": { + "title": "CustomSellmeier", + "description": "A spatially varying dispersive medium described by the Sellmeier model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None, um^2)]. List of Sellmeier (:math:`B_i, C_i`) coefficients.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the refractive index is described by:\n\n .. math::\n\n n(\\lambda)^2 = 1 + \\sum_i \\frac{B_i \\lambda^2}{\\lambda^2 - C_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> b1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> c1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> sellmeier_medium = CustomSellmeier(coeffs=[(b1,c1),])\n>>> eps = sellmeier_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Sellmeier`\n A dispersive medium described by the Sellmeier model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomSellmeier", + "enum": [ + "CustomSellmeier" + ], + "type": "string" + }, + "coeffs": { + "title": "Coefficients", + "description": "List of Sellmeier (:math:`B_i, C_i`) coefficients.", + "units": [ + null, + "um^2" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "coeffs" + ], + "additionalProperties": false + }, + "CustomLorentz": { + "title": "CustomLorentz", + "description": "A spatially varying dispersive medium described by the Lorentz model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), Hz, Hz)]. List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i f_i^2}{f_i^2 - 2jf\\delta_i - f^2}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> d_epsilon = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> lorentz_medium = CustomLorentz(eps_inf=eps_inf, coeffs=[(d_epsilon,f,delta),])\n>>> eps = lorentz_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`CustomPoleResidue`:\n A spatially varying dispersive medium described by the pole-residue pair model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomLorentz", + "enum": [ + "CustomLorentz" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", + "units": [ + "None (relative permittivity)", + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDebye": { + "title": "CustomDebye", + "description": "A spatially varying dispersive medium described by the Debye model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (None (relative permittivity), sec)]. List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty + \\sum_i\n \\frac{\\Delta\\epsilon_i}{1 - jf\\tau_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(1+np.random.random((5, 6, 7)), coords=coords)\n>>> eps1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> tau1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> debye_medium = CustomDebye(eps_inf=eps_inf, coeffs=[(eps1,tau1),])\n>>> eps = debye_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Debye`\n A dispersive medium described by the Debye model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDebye", + "enum": [ + "CustomDebye" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", + "units": [ + "None (relative permittivity)", + "sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomDrude": { + "title": "CustomDrude", + "description": "A spatially varying dispersive medium described by the Drude model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\ncoeffs : Tuple[tuple[Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]], Union[tidy3d.components.data.data_array.SpatialDataArray, Annotated[Union[tidy3d.components.data.unstructured.triangular.TriangularGridDataset, tidy3d.components.data.unstructured.tetrahedral.TetrahedralGridDataset], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]], ...]\n [units = (Hz, Hz)]. List of (:math:`f_i, \\delta_i`) values for model.\ninterp_method : Literal['nearest', 'linear'] = nearest\n Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.\nsubpixel : bool = False\n If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.\n\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(f) = \\epsilon_\\infty - \\sum_i\n \\frac{ f_i^2}{f^2 + jf\\delta_i}\n\nExample\n-------\n>>> x = np.linspace(-1, 1, 5)\n>>> y = np.linspace(-1, 1, 6)\n>>> z = np.linspace(-1, 1, 7)\n>>> coords = dict(x=x, y=y, z=z)\n>>> eps_inf = SpatialDataArray(np.ones((5, 6, 7)), coords=coords)\n>>> f1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> delta1 = SpatialDataArray(np.random.random((5, 6, 7)), coords=coords)\n>>> drude_medium = CustomDrude(eps_inf=eps_inf, coeffs=[(f1,delta1),])\n>>> eps = drude_medium.eps_model(200e12)\n\nSee Also\n--------\n\n:class:`Drude`:\n A dispersive medium described by the Drude model.\n\n**Notebooks**\n * `Fitting dispersive material models <../../notebooks/Fitting.html>`_\n\n**Lectures**\n * `Modeling dispersive material in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomDrude", + "enum": [ + "CustomDrude" + ], + "type": "string" + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + "coeffs": { + "title": "Coefficients", + "description": "List of (:math:`f_i, \\delta_i`) values for model.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + }, + { + "anyOf": [ + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "oneOf": [ + { + "$ref": "#/definitions/TriangularGridDataset" + }, + { + "$ref": "#/definitions/TetrahedralGridDataset" + } + ] + } + ] + } + ] + } + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain permittivity values that are not supplied at the Yee grids; For grids outside the range of the supplied data, extrapolation will be applied. When the extrapolated value is smaller (greater) than the minimal (maximal) of the supplied data, the extrapolated value will take the minimal (maximal) of the supplied data.", + "default": "nearest", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "If ``True``, apply the subpixel averaging method specified by ``Simulation``'s field ``subpixel`` for this type of material on the interface of the structure, including exterior boundary and intersection interfaces with other structures.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "eps_inf", + "coeffs" + ], + "additionalProperties": false + }, + "CustomAnisotropicMedium": { + "title": "CustomAnisotropicMedium", + "description": "Diagonally anisotropic medium with spatially varying permittivity in each component.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.\ninterp_method : Optional[Literal['nearest', 'linear']] = None\n When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.\nsubpixel : Optional[bool] = None\n This field is ignored. Please set ``subpixel`` in each component\n\nNote\n----\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> Nx, Ny, Nz = 10, 9, 8\n>>> x = np.linspace(-1, 1, Nx)\n>>> y = np.linspace(-1, 1, Ny)\n>>> z = np.linspace(-1, 1, Nz)\n>>> coords = dict(x=x, y=y, z=z)\n>>> permittivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> conductivity= SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords)\n>>> medium_xx = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> medium_yy = CustomMedium(permittivity=permittivity, conductivity=conductivity)\n>>> d_epsilon = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> f = SpatialDataArray(1+np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> delta = SpatialDataArray(np.random.random((Nx, Ny, Nz)), coords=coords)\n>>> medium_zz = CustomLorentz(eps_inf=permittivity, coeffs=[(d_epsilon,f,delta),])\n>>> anisotropic_dielectric = CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz)\n\nSee Also\n--------\n\n:class:`AnisotropicMedium`\n Diagonally anisotropic medium.\n\n**Notebooks**\n * `Broadband polarizer assisted by anisotropic metamaterial <../../notebooks/SWGBroadbandPolarizer.html>`_\n * `Thin film lithium niobate adiabatic waveguide coupler <../../notebooks/AdiabaticCouplerLN.html>`_\n * `Defining fully anisotropic materials <../../notebooks/FullyAnisotropic.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "CustomAnisotropicMedium", + "enum": [ + "CustomAnisotropicMedium" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomMedium": "#/definitions/CustomMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomMedium" + } + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "When the value is 'None', each component will follow its own interpolation method. When the value is other than 'None', the interpolation method specified by this field will override the one in each component.", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This field is ignored. Please set ``subpixel`` in each component", + "type": "boolean" + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "LinearHeatPerturbation": { + "title": "LinearHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a linear function of\ntemperature.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n [units = K]. Temperature range in which perturbation model is valid.\ntemperature_ref : NonNegativeFloat\n [units = K]. Temperature at which perturbation is zero.\ncoeff : Union[float, tidycomplex, ComplexNumber]\n [units = 1/K]. Sensitivity (derivative) of perturbation with respect to temperature.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{coeff} \\times (T - \\text{temperature\\_ref}),\n\n where ``coeff`` is the parameter's sensitivity (thermo-optic coefficient) to temperature and\n ``temperature_ref`` is the reference temperature point. A temperature range in which such\n a model is deemed accurate may be provided as a field ``temperature_range``\n (default: ``[0, inf]``). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.0001,\n... temperature_range=[200, 500],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearHeatPerturbation", + "enum": [ + "LinearHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "temperature_ref": { + "title": "Reference temperature", + "description": "Temperature at which perturbation is zero.", + "units": "K", + "minimum": 0, + "type": "number" + }, + "coeff": { + "title": "Thermo-optic Coefficient", + "description": "Sensitivity (derivative) of perturbation with respect to temperature.", + "units": "1/K", + "anyOf": [ + { + "type": "number" + }, + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + } + }, + "required": [ + "temperature_ref", + "coeff" + ], + "additionalProperties": false + }, + "CustomHeatPerturbation": { + "title": "CustomHeatPerturbation", + "description": "Specifies parameter's perturbation due to thermal effects as a custom function of\ntemperature defined as an array of perturbation values at sample temperature points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n [units = K]. Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.\nperturbation_values : HeatDataArray\n Sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\n Notes\n -----\n\n The linear\n interpolation is used to calculate perturbation values between sample temperature points. For\n temperature values outside of the provided sample region the perturbation value is extrapolated\n as a constant.\n The temperature range, ``temperature_range``, in which the perturbation model is assumed to be\n accurate is calculated automatically as the minimal and maximal sample temperature points.\n Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``temperature_range`` due to perturbations and\n raise a warning if this check fails. A warning is also issued if the perturbation model is\n evaluated outside of ``temperature_range``.\n\n .. TODO link to relevant example new\n\nExample\n-------\n>>> from tidy3d import HeatDataArray\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomHeatPerturbation", + "enum": [ + "CustomHeatPerturbation" + ], + "type": "string" + }, + "temperature_range": { + "title": "Temperature range", + "description": "Temperature range in which perturbation model is valid. For :class:`.CustomHeatPerturbation` this field is computed automatically based on temperature sample points provided in ``perturbation_values``.", + "units": "K", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "Sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "LinearChargePerturbation": { + "title": "LinearChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a linear function of\nelectron and hole densities:\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of electrons densities in which perturbation model is valid.\nhole_range : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, inf)\n Range of holes densities in which perturbation model is valid.\nelectron_ref : NonNegativeFloat\n [units = 1/cm^3]. Electron density value at which there is no perturbation due to electrons's presence.\nhole_ref : NonNegativeFloat\n [units = 1/cm^3]. Hole density value at which there is no perturbation due to holes' presence.\nelectron_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to electron density.\nhole_coeff : float\n [units = cm^3]. Sensitivity (derivative) of perturbation with respect to hole density.\n\nNotes\n-----\n\n .. math::\n\n \\Delta X (T) = \\text{electron\\_coeff} \\times (N_e - \\text{electron\\_ref})\n + \\text{hole\\_coeff} \\times (N_h - \\text{hole\\_ref}),\n\n where ``electron_coeff`` and ``hole_coeff`` are the parameter's sensitivities to electron and\n hole densities, while ``electron_ref`` and ``hole_ref`` are reference electron and hole density\n values. Ranges of electron and hole densities in which such\n a model is deemed accurate may be provided as fields ``electron_range`` and ``hole_range``\n (default: ``[0, inf]`` each). Wherever is applied, Tidy3D will check that the parameter's value\n does not go out of its physical bounds within ``electron_range`` x ``hole_range`` due to\n perturbations and raise a warning if this check fails. A warning is also issued if\n the perturbation model is evaluated outside of ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearChargePerturbation", + "enum": [ + "LinearChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid.", + "default": [ + 0, + Infinity + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "electron_ref": { + "title": "Reference Electron Density", + "description": "Electron density value at which there is no perturbation due to electrons's presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "hole_ref": { + "title": "Reference Hole Density", + "description": "Hole density value at which there is no perturbation due to holes' presence.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "electron_coeff": { + "title": "Sensitivity to Electron Density", + "description": "Sensitivity (derivative) of perturbation with respect to electron density.", + "units": "cm^3", + "type": "number" + }, + "hole_coeff": { + "title": "Sensitivity to Hole Density", + "description": "Sensitivity (derivative) of perturbation with respect to hole density.", + "units": "cm^3", + "type": "number" + } + }, + "required": [ + "electron_ref", + "hole_ref", + "electron_coeff", + "hole_coeff" + ], + "additionalProperties": false + }, + "CustomChargePerturbation": { + "title": "CustomChargePerturbation", + "description": "Specifies parameter's perturbation due to free carrier effects as a custom function of\nelectron and hole densities defined as a two-dimensional array of perturbation values at sample\nelectron and hole density points.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nelectron_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nhole_range : Optional[Tuple[NonNegativeFloat, NonNegativeFloat]] = None\n Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``\nperturbation_values : ChargeDataArray\n 2D array (vs electron and hole densities) of sampled perturbation values.\ninterp_method : Literal['nearest', 'linear'] = linear\n Interpolation method to obtain perturbation values between sample points.\n\nNotes\n-----\n\n The linear interpolation is used to calculate perturbation\n values between sample points. For electron and hole density values outside of the provided\n sample region the perturbation value is extrapolated as a constant.\n The electron and hole density ranges, ``electron_range`` and ``hole_range``, in which\n the perturbation model is assumed to be accurate is calculated automatically as the minimal and\n maximal density values provided in ``perturbation_values``. Wherever is applied, Tidy3D will\n check that the parameter's value does not go out of its physical bounds within\n ``electron_range`` x ``hole_range`` due to perturbations and raise a warning if this check\n fails. A warning is also issued if the perturbation model is evaluated outside of\n ``electron_range`` x ``hole_range``.\n\n .. TODO add example here and links\n\nExample\n-------\n>>> from tidy3d import ChargeDataArray\n>>> perturbation_data = ChargeDataArray(\n... [[0.001, 0.002, 0.004], [0.003, 0.002, 0.001]],\n... coords=dict(n=[2e15, 2e19], p=[1e16, 1e17, 1e18]),\n... )\n>>> charge_perturb = CustomChargePerturbation(\n... perturbation_values=perturbation_data,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomChargePerturbation", + "enum": [ + "CustomChargePerturbation" + ], + "type": "string" + }, + "electron_range": { + "title": "Electron Density Range", + "description": "Range of electrons densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "hole_range": { + "title": "Hole Density Range", + "description": "Range of holes densities in which perturbation model is valid. For :class:`.CustomChargePerturbation` this field is computed automatically based on provided ``perturbation_values``", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "perturbation_values": { + "title": "DataArray", + "description": "2D array (vs electron and hole densities) of sampled perturbation values.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "interp_method": { + "title": "Interpolation method", + "description": "Interpolation method to obtain perturbation values between sample points.", + "default": "linear", + "enum": [ + "nearest", + "linear" + ], + "type": "string" + } + }, + "required": [ + "perturbation_values" + ], + "additionalProperties": false + }, + "ParameterPerturbation": { + "title": "ParameterPerturbation", + "description": "Stores information about parameter perturbations due to different physical effect. If both\nheat and charge perturbation models are included their effects are superimposed.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nheat : Union[LinearHeatPerturbation, CustomHeatPerturbation] = None\n Heat perturbation to apply.\ncharge : Union[LinearChargePerturbation, CustomChargePerturbation] = None\n Charge perturbation to apply.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, CustomHeatPerturbation, HeatDataArray\n>>>\n>>> perturbation_data = HeatDataArray([0.001, 0.002, 0.004], coords=dict(T=[250, 300, 350]))\n>>> heat_perturb = CustomHeatPerturbation(\n... perturbation_values=perturbation_data\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... electron_range=[0, 1e19],\n... hole_ref=0,\n... hole_coeff=0.0002,\n... hole_range=[0, 2e19],\n... )\n>>> param_perturb = ParameterPerturbation(heat=heat_perturb, charge=charge_perturb)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "heat": { + "title": "Heat Perturbation", + "description": "Heat perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearHeatPerturbation": "#/definitions/LinearHeatPerturbation", + "CustomHeatPerturbation": "#/definitions/CustomHeatPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearHeatPerturbation" + }, + { + "$ref": "#/definitions/CustomHeatPerturbation" + } + ] + }, + "charge": { + "title": "Charge Perturbation", + "description": "Charge perturbation to apply.", + "discriminator": { + "propertyName": "type", + "mapping": { + "LinearChargePerturbation": "#/definitions/LinearChargePerturbation", + "CustomChargePerturbation": "#/definitions/CustomChargePerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LinearChargePerturbation" + }, + { + "$ref": "#/definitions/CustomChargePerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "ParameterPerturbation", + "enum": [ + "ParameterPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PermittivityPerturbation": { + "title": "PermittivityPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\npermittivity and conductivity.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_eps : Optional[ParameterPerturbation] = None\n Perturbation model for permittivity.\ndelta_sigma : Optional[ParameterPerturbation] = None\n Perturbation model for conductivity.\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, PermittivityPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> delta_eps = ParameterPerturbation(heat=heat_perturb)\n>>> delta_sigma = ParameterPerturbation(charge=charge_perturb)\n>>> permittivity_pb = PermittivityPerturbation(delta_eps=delta_eps, delta_sigma=delta_sigma)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_eps": { + "title": "Permittivity Perturbation", + "description": "Perturbation model for permittivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_sigma": { + "title": "Conductivity Perturbation", + "description": "Perturbation model for conductivity.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PermittivityPerturbation", + "enum": [ + "PermittivityPerturbation" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IndexPerturbation": { + "title": "IndexPerturbation", + "description": "A general medium perturbation model which is defined through perturbation to\nrefractive index, n and k.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndelta_n : Optional[ParameterPerturbation] = None\n Perturbation of the real part of refractive index.\ndelta_k : Optional[ParameterPerturbation] = None\n Perturbation of the imaginary part of refractive index.\nfreq : NonNegativeFloat\n [units = Hz]. Frequency to evaluate permittivity at (Hz).\n\nExample\n-------\n>>> from tidy3d import LinearChargePerturbation, LinearHeatPerturbation, IndexPerturbation, C_0\n>>>\n>>> heat_perturb = LinearHeatPerturbation(\n... temperature_ref=300,\n... coeff=0.001,\n... )\n>>> charge_perturb = LinearChargePerturbation(\n... electron_ref=0,\n... electron_coeff=0.0001,\n... hole_ref=0,\n... hole_coeff=0.0002,\n... )\n>>> dn_pb = ParameterPerturbation(heat=heat_perturb)\n>>> dk_pb = ParameterPerturbation(charge=charge_perturb)\n>>> index_pb = IndexPerturbation(delta_n=dn_pb, delta_k=dk_pb, freq=C_0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "delta_n": { + "title": "Refractive Index Perturbation", + "description": "Perturbation of the real part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "delta_k": { + "title": "Exctinction Coefficient Perturbation", + "description": "Perturbation of the imaginary part of refractive index.", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "freq": { + "title": "Frequency", + "description": "Frequency to evaluate permittivity at (Hz).", + "units": "Hz", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "IndexPerturbation", + "enum": [ + "IndexPerturbation" + ], + "type": "string" + } + }, + "required": [ + "freq" + ], + "additionalProperties": false + }, + "PerturbationMedium": { + "title": "PerturbationMedium", + "description": "Dispersionless medium with perturbations. Perturbation model can be defined either directly\nthrough providing ``permittivity_perturbation`` and ``conductivity_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : Union[ConstrainedFloatValue, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : Union[float, Box] = 0.0\n [units = S/um]. Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.\npermittivity_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. List of heat and/or charge perturbations to permittivity.\nconductivity_perturbation : Optional[ParameterPerturbation] = None\n [units = S/um]. List of heat and/or charge perturbations to permittivity.\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> dielectric = PerturbationMedium(\n... permittivity=4.0,\n... permittivity_perturbation=ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... ),\n... name='my_medium',\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationMedium", + "enum": [ + "PerturbationMedium" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "minimum": 1.0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "conductivity": { + "title": "Conductivity", + "description": "Electric conductivity. Defined such that the imaginary part of the complex permittivity at angular frequency omega is given by conductivity/omega.", + "default": 0.0, + "units": "S/um", + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "permittivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "conductivity_perturbation": { + "title": "Permittivity Perturbation", + "description": "List of heat and/or charge perturbations to permittivity.", + "units": "S/um", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + }, + "additionalProperties": false + }, + "PerturbationPoleResidue": { + "title": "PerturbationPoleResidue", + "description": "A dispersive medium described by the pole-residue pair model with perturbations.\nPerturbation model can be defined either directly\nthrough providing ``eps_inf_perturbation`` and ``poles_perturbation`` or via\nproviding a specific perturbation model (:class:`PermittivityPerturbation`,\n:class:`IndexPerturbation`) as ``perturbaiton_spec``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsubpixel : bool = True\n This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.\nperturbation_spec : Union[PermittivityPerturbation, IndexPerturbation, NoneType] = None\n Specification of medium perturbation as one of predefined types.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\neps_inf : Union[PositiveFloat, Box] = 1.0\n [units = None (relative permittivity)]. Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles : Tuple[tuple[Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box], Union[tidy3d.components.types.tidycomplex, tidy3d.components.types.ComplexNumber, autograd.tracer.Box]], ...] = ()\n [units = (rad/sec, rad/sec)]. Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.\neps_inf_perturbation : Optional[ParameterPerturbation] = None\n [units = None (relative permittivity)]. Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).\npoles_perturbation : Optional[Tuple[tuple[Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation], Optional[tidy3d.components.parameter_perturbation.ParameterPerturbation]], ...]] = None\n [units = (rad/sec, rad/sec)]. Perturbations to poles of the model.\n\nNotes\n-----\n\n The frequency-dependence of the complex-valued permittivity is described by:\n\n .. math::\n\n \\epsilon(\\omega) = \\epsilon_\\infty - \\sum_i\n \\left[\\frac{c_i}{j \\omega + a_i} +\n \\frac{c_i^*}{j \\omega + a_i^*}\\right]\n\nExample\n-------\n>>> from tidy3d import ParameterPerturbation, LinearHeatPerturbation\n>>> c0_perturbation = ParameterPerturbation(\n... heat=LinearHeatPerturbation(temperature_ref=300, coeff=0.0001),\n... )\n>>> pole_res = PerturbationPoleResidue(\n... eps_inf=2.0,\n... poles=[((-1+2j), (3+4j)), ((-5+6j), (7+8j))],\n... poles_perturbation=[(None, c0_perturbation), (None, None)],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "subpixel": { + "title": "Subpixel averaging", + "description": "This value will be transferred to the resulting custom medium. That is, if ``True``, the subpixel averaging will be applied to the custom medium. The type of subpixel averaging method applied is specified in ``Simulation``'s field ``subpixel``. If the resulting medium is not a custom medium (no perturbations), this field does not have an effect.", + "default": true, + "type": "boolean" + }, + "perturbation_spec": { + "title": "Perturbation Spec", + "description": "Specification of medium perturbation as one of predefined types.", + "discriminator": { + "propertyName": "type", + "mapping": { + "PermittivityPerturbation": "#/definitions/PermittivityPerturbation", + "IndexPerturbation": "#/definitions/IndexPerturbation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/PermittivityPerturbation" + }, + { + "$ref": "#/definitions/IndexPerturbation" + } + ] + }, + "type": { + "title": "Type", + "default": "PerturbationPoleResidue", + "enum": [ + "PerturbationPoleResidue" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "eps_inf": { + "title": "Epsilon at Infinity", + "description": "Relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "default": 1.0, + "units": "None (relative permittivity)", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "poles": { + "title": "Poles", + "description": "Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", + "default": [], + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + } + }, + "eps_inf_perturbation": { + "title": "Perturbation of Epsilon at Infinity", + "description": "Perturbations to relative permittivity at infinite frequency (:math:`\\epsilon_\\infty`).", + "units": "None (relative permittivity)", + "allOf": [ + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + }, + "poles_perturbation": { + "title": "Perturbations of Poles", + "description": "Perturbations to poles of the model.", + "units": [ + "rad/sec", + "rad/sec" + ], + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "$ref": "#/definitions/ParameterPerturbation" + }, + { + "$ref": "#/definitions/ParameterPerturbation" + } + ] + } + } + }, + "additionalProperties": false + }, + "Box": { + "title": "Box", + "description": "Rectangular prism.\n Also base class for :class:`Simulation`, :class:`Monitor`, and :class:`Source`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\n\nExample\n-------\n>>> b = Box(center=(1,2,3), size=(2,2,2))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Box", + "enum": [ + "Box" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "Sphere": { + "title": "Sphere", + "description": "Spherical geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nradius : NonNegativeFloat\n [units = um]. Radius of geometry.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\n\nExample\n-------\n>>> b = Sphere(center=(1,2,3), radius=2)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Sphere", + "enum": [ + "Sphere" + ], + "type": "string" + }, + "radius": { + "title": "Radius", + "description": "Radius of geometry.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + }, + "required": [ + "radius" + ], + "additionalProperties": false + }, + "Cylinder": { + "title": "Cylinder", + "description": "Cylindrical geometry with optional sidewall angle along axis\ndirection. When ``sidewall_angle`` is nonzero, the shape is a\nconical frustum or a cone.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> c = Cylinder(center=(1,2,3), radius=2, length=5, axis=2)\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../../notebooks/THzDemultiplexerFilter.html>`_\n* `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Cylinder", + "enum": [ + "Cylinder" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([(0,0), (1,0), (1,1)])\n>>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolySlab", + "enum": [ + "PolySlab" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).\nsidewall_angle : float = 0.0\n [units = rad]. Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0 (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "sidewall_angle": { + "title": "Sidewall angle", + "description": "Angle of the sidewall. ``sidewall_angle=0`` (default) specifies a vertical wall; ``0>> vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])\n>>> faces = np.array([[1, 2, 3], [0, 3, 2], [0, 1, 3], [0, 2, 1]])\n>>> stl_geom = TriangleMesh.from_vertices_faces(vertices, faces)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TriangleMesh", + "enum": [ + "TriangleMesh" + ], + "type": "string" + }, + "mesh_dataset": { + "title": "Surface mesh data", + "description": "Surface mesh data.", + "allOf": [ + { + "$ref": "#/definitions/TriangleMeshDataset" + } + ] + } + }, + "required": [ + "mesh_dataset" + ], + "additionalProperties": false + }, + "GeometryGroup": { + "title": "GeometryGroup", + "description": "A collection of Geometry objects that can be called as a single geometry object.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometries : ForwardRef('tuple[annotate_type(GeometryType), ...]')\n Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GeometryGroup", + "enum": [ + "GeometryGroup" + ], + "type": "string" + }, + "geometries": { + "title": "Geometries", + "description": "Tuple of geometries in a single grouping. Can provide significant performance enhancement in ``Structure`` when all geometries are assigned the same medium.", + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + } + }, + "required": [ + "geometries" + ], + "additionalProperties": false + }, + "ClipOperation": { + "title": "ClipOperation", + "description": "Class representing the result of a set operation between geometries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\noperation : Literal['union', 'intersection', 'difference', 'symmetric_difference']\n Operation to be performed between geometries.\ngeometry_a : ForwardRef('annotate_type(GeometryType)')\n First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.\ngeometry_b : ForwardRef('annotate_type(GeometryType)')\n Second operand for the set operation. It can also be any geometry type.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ClipOperation", + "enum": [ + "ClipOperation" + ], + "type": "string" + }, + "operation": { + "title": "Operation Type", + "description": "Operation to be performed between geometries.", + "enum": [ + "union", + "intersection", + "difference", + "symmetric_difference" + ], + "type": "string" + }, + "geometry_a": { + "title": "Geometry A", + "description": "First operand for the set operation. It can be any geometry type, including :class:`GeometryGroup`.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "geometry_b": { + "title": "Geometry B", + "description": "Second operand for the set operation. It can also be any geometry type.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + } + }, + "required": [ + "operation", + "geometry_a", + "geometry_b" + ], + "additionalProperties": false + }, + "Transformed": { + "title": "Transformed", + "description": "Class representing a transformed geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : ForwardRef('annotate_type(GeometryType)')\n Base geometry to be transformed.\ntransform : ArrayLike[dtype=float, ndim=2, shape=(4, 4)] = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]\n Transform matrix applied to the base geometry.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Transformed", + "enum": [ + "Transformed" + ], + "type": "string" + }, + "geometry": { + "title": "Geometry", + "description": "Base geometry to be transformed.", + "anyOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "transform": { + "title": "Transform", + "description": "Transform matrix applied to the base geometry.", + "default": [ + [ + 1.0, + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 1.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 1.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0, + 1.0 + ] + ], + "type": "ArrayLike" + } + }, + "required": [ + "geometry" + ], + "additionalProperties": false + }, + "Medium2D": { + "title": "Medium2D", + "description": "2D diagonally anisotropic medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nss : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.\ntt : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium]\n Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.\n\nNotes\n-----\n\n Only diagonal anisotropy is currently supported.\n\nExample\n-------\n>>> drude_medium = Drude(eps_inf=2.0, coeffs=[(1,2), (3,4)])\n>>> medium2d = Medium2D(ss=drude_medium, tt=drude_medium)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "Medium2D", + "enum": [ + "Medium2D" + ], + "type": "string" + }, + "ss": { + "title": "SS Component", + "description": "Medium describing the ss-component of the diagonal permittivity tensor. The ss-component refers to the in-plane dimension of the medium that is the first component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the xx-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + }, + "tt": { + "title": "TT Component", + "description": "Medium describing the tt-component of the diagonal permittivity tensor. The tt-component refers to the in-plane dimension of the medium that is the second component in order of 'x', 'y', 'z'. If the 2D material is normal to the y-axis, for example, then this determines the zz-component of the corresponding 3D medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + } + ] + } + }, + "required": [ + "ss", + "tt" + ], + "additionalProperties": false + }, + "AnisotropicMediumFromMedium2D": { + "title": "AnisotropicMediumFromMedium2D", + "description": "The same as ``AnisotropicMedium``, but converted from Medium2D.\n(This class is for internal use only)\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : Optional[bool] = None\n This field is ignored. Please set ``allow_gain`` in each component\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\nxx : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the xx-component of the diagonal permittivity tensor.\nyy : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the yy-component of the diagonal permittivity tensor.\nzz : Union[Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium, PMCMedium]\n Medium describing the zz-component of the diagonal permittivity tensor.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "This field is ignored. Please set ``allow_gain`` in each component", + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "AnisotropicMediumFromMedium2D", + "enum": [ + "AnisotropicMediumFromMedium2D" + ], + "type": "string" + }, + "xx": { + "title": "XX Component", + "description": "Medium describing the xx-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "yy": { + "title": "YY Component", + "description": "Medium describing the yy-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + }, + "zz": { + "title": "ZZ Component", + "description": "Medium describing the zz-component of the diagonal permittivity tensor.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + } + ] + } + }, + "required": [ + "xx", + "yy", + "zz" + ], + "additionalProperties": false + }, + "ChargeConductorMedium": { + "title": "ChargeConductorMedium", + "description": "Conductor medium for conduction simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nconductivity : PositiveFloat\n [units = S/um]. Electric conductivity of material in units of S/um.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeConductorMedium(conductivity=3)\n\nNote\n----\n A relative permittivity will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeConductorMedium", + "enum": [ + "ChargeConductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "conductivity": { + "title": "Electric conductivity", + "description": "Electric conductivity of material in units of S/um.", + "units": "S/um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "conductivity" + ], + "additionalProperties": false + }, + "ChargeInsulatorMedium": { + "title": "ChargeInsulatorMedium", + "description": "Insulating medium. Conduction simulations will not solve for electric\npotential in a structure that has a medium with this 'charge'.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\n\nExample\n-------\n>>> import tidy3d as td\n>>> solid = td.ChargeInsulatorMedium()\n>>> solid2 = td.ChargeInsulatorMedium(permittivity=1.1)\n\nNote\n----\n A relative permittivity :math:`\\varepsilon` will be assumed 1 if no value is specified.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "ChargeInsulatorMedium", + "enum": [ + "ChargeInsulatorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + } + }, + "additionalProperties": false + }, + "CaugheyThomasMobility": { + "title": "CaugheyThomasMobility", + "description": "The Caughey-Thomas temperature-dependent carrier mobility model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu_min : PositiveFloat\n Minimum electron mobility at reference temperature (300K) in cm^2/V-s. \nmu : PositiveFloat\n Reference mobility at reference temperature (300K) in cm^2/V-s\nexp_2 : float\n exp_N : PositiveFloat\n Exponent for doping dependence of mobility at reference temperature (300K).\nref_N : PositiveFloat\n Reference doping at reference temperature (300K) in #/cm^3.\nexp_1 : float\n Exponent of thermal dependence of minimum mobility.\nexp_3 : float\n Exponent of thermal dependence of reference doping.\nexp_4 : float\n Exponent of thermal dependence of the doping exponent effect.\n\nNotes\n-----\n The general form of the Caughey-Thomas mobility model [1]_ is of the form:\n\n .. math::\n\n \\mu_0 = \\frac{\\mu_{max} - \\mu_{min}}{1 + \\left(N/N_{ref}\\right)^z} + \\mu_{min}\n\nwhere :math:`\\mu_0` represents the low-field mobility and :math:`N` is the total doping (acceptors + donors).\n:math:`\\mu_{max}`, :math:`\\mu_{min}`, :math:`z`, and :math:`N_{ref}` are temperature dependent,\nthe dependence being of the form\n\n.. math::\n\n \\phi = \\phi_{ref} \\left( \\frac{T}{T_{ref}}\\right)^\\alpha\n\nand :math:`T_{ref}` is taken to be 300K.\n\nThe complete form (with temperature effects) for the low-field mobility can be written as\n\n.. math::\n\n \\mu_0 = \\frac{\\mu_{max}(\\frac{T}{T_{ref}})^{\\alpha_2} - \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}}{1 + \\left(N/N_{ref}(\\frac{T}{T_{ref}})^{\\alpha_3}\\right)^{\\alpha_N(\\frac{T}{T_{ref}})^{\\alpha_4}}} + \\mu_{min}(\\frac{T}{T_{ref}})^{\\alpha_1}\n\nThe following table maps the symbols used in the equations above with the names used in the code:\n\n.. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`\\mu_{min}`\n - ``mu_min``\n - Minimum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\mu_{max}`\n - ``mu_n``\n - Maximum low-field mobility for :math:`n` and :math:`p`\n * - :math:`\\alpha_1`\n - ``exp_1``\n - Exponent for temperature dependence of the minimum mobility coefficient\n * - :math:`\\alpha_2`\n - ``exp_2``\n - Exponent for temperature dependence of the maximum mobility coefficient\n * - :math:`\\alpha_N`\n - ``exp_N``\n - Exponent for doping dependence.\n * - :math:`\\alpha_4`\n - ``exp_4``\n - Exponent for the temperature dependence of the exponent :math:`\\alpha_N`\n * - :math:`N_{ref}`\n - ``ref_N``,\n - Reference doping parameter\n\n\n.. [1] M. Caughey and R.E. Thomas. Carrier mobilities in silicon empirically related to doping\n and field. Proceedings of the IEEE, 55(12):2192\u20132193, December 1967\n\nExample\n-------\n >>> import tidy3d as td\n >>> mobility_Si_n = td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n >>> mobility_Si_p = td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... )\n\n\nWarning\n-------\nThere are some current limitations of this model:\n\n- High electric field effects not yet supported.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu_min": { + "title": "$\\mu_{min}$ Minimum electron mobility", + "description": "Minimum electron mobility at reference temperature (300K) in cm^2/V-s. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "mu": { + "title": "Reference mobility", + "description": "Reference mobility at reference temperature (300K) in cm^2/V-s", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_2": { + "title": "Exponent for temperature dependent behavior of reference mobility", + "type": "number" + }, + "exp_N": { + "title": "Exponent for doping dependence of mobility.", + "description": "Exponent for doping dependence of mobility at reference temperature (300K).", + "exclusiveMinimum": 0, + "type": "number" + }, + "ref_N": { + "title": "Reference doping", + "description": "Reference doping at reference temperature (300K) in #/cm^3.", + "exclusiveMinimum": 0, + "type": "number" + }, + "exp_1": { + "title": "Exponent of thermal dependence of minimum mobility.", + "description": "Exponent of thermal dependence of minimum mobility.", + "type": "number" + }, + "exp_3": { + "title": "Exponent of thermal dependence of reference doping.", + "description": "Exponent of thermal dependence of reference doping.", + "type": "number" + }, + "exp_4": { + "title": "Exponent of thermal dependence of the doping exponent effect.", + "description": "Exponent of thermal dependence of the doping exponent effect.", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CaugheyThomasMobility", + "enum": [ + "CaugheyThomasMobility" + ], + "type": "string" + } + }, + "required": [ + "mu_min", + "mu", + "exp_2", + "exp_N", + "ref_N", + "exp_1", + "exp_3", + "exp_4" + ], + "additionalProperties": false + }, + "ConstantMobilityModel": { + "title": "ConstantMobilityModel", + "description": "Constant mobility model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmu : NonNegativeFloat\n [units = cm\u00b2/V-s]. Mobility\n\nExample\n-------\n>>> import tidy3d as td\n>>> mobility_model = td.ConstantMobilityModel(mu=1500)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "mu": { + "title": "Mobility", + "description": "Mobility", + "units": "cm\u00b2/V-s", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ConstantMobilityModel", + "enum": [ + "ConstantMobilityModel" + ], + "type": "string" + } + }, + "required": [ + "mu" + ], + "additionalProperties": false + }, + "AugerRecombination": { + "title": "AugerRecombination", + "description": "Parameters for the Auger recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nc_n : PositiveFloat\n Constant for electrons in cm^6/s\nc_p : PositiveFloat\n Constant for holes in cm^6/s\n\nNotes\n-----\n\n The Auger recombination rate ``R_A`` is primarily defined by the electrons and holes Auger recombination\n coefficients, :math:`C_n` and :math:`C_p`, respectively.\n\n .. math::\n\n R_A = \\left( C_n n + C_p p \\right) \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32,\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "c_n": { + "title": "Constant for electrons", + "description": "Constant for electrons in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "c_p": { + "title": "Constant for holes", + "description": "Constant for holes in cm^6/s", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AugerRecombination", + "enum": [ + "AugerRecombination" + ], + "type": "string" + } + }, + "required": [ + "c_n", + "c_p" + ], + "additionalProperties": false + }, + "RadiativeRecombination": { + "title": "RadiativeRecombination", + "description": "Defines the parameters for the radiative recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr_const : float\n Radiation constant in cm^3/s\n\nNotes\n-----\n\n This is a direct recombination model primarily defined by a radiative recombination coefficient :math:`R_{\\text{rad}}`.\n\n .. math::\n\n R_{\\text{rad}} = C \\left( np - n_0 p_0 \\right)\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r_const": { + "title": "Radiation constant in cm^3/s", + "description": "Radiation constant in cm^3/s", + "type": "number" + }, + "type": { + "title": "Type", + "default": "RadiativeRecombination", + "enum": [ + "RadiativeRecombination" + ], + "type": "string" + } + }, + "required": [ + "r_const" + ], + "additionalProperties": false + }, + "FossumCarrierLifetime": { + "title": "FossumCarrierLifetime", + "description": "Parameters for the Fossum carrier lifetime model\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_300 : PositiveFloat\n [units = sec]. Carrier lifetime at 300K\nalpha_T : float\n Exponent for thermal dependence\nN0 : PositiveFloat\n [units = 1/cm^3]. Reference concentration\nA : float\n Constant A\nB : float\n Constant B\nC : float\n Constant C\nalpha : float\n Exponent constant\n\nNotes\n-----\n\n This model expresses the carrier lifetime as a function of the temperature and doping concentration.\n\n .. math::\n\n \\tau = \\frac{\\tau_{300} \\left( T/300 \\right)^\\alpha_T}{A + B (N/N_0) + C (N/N_0)^\\alpha}\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.FossumCarrierLifetime(\n ... tau_300=3.3e-6,\n ... alpha_T=-0.5,\n ... N0=7.1e15,\n ... A=1,\n ... B=0,\n ... C=1,\n ... alpha=1\n ... )\n\nReferences\n----------\n\n Fossum, J. G., and D. S. Lee. \"A physical model for the dependence of carrier lifetime on doping density in nondegenerate silicon.\" Solid-State Electronics 25.8 (1982): 741-747.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_300": { + "title": "Tau at 300K", + "description": "Carrier lifetime at 300K", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "alpha_T": { + "title": "Exponent for thermal dependence", + "description": "Exponent for thermal dependence", + "type": "number" + }, + "N0": { + "title": "Reference concentration", + "description": "Reference concentration", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "A": { + "title": "Constant A", + "description": "Constant A", + "type": "number" + }, + "B": { + "title": "Constant B", + "description": "Constant B", + "type": "number" + }, + "C": { + "title": "Constant C", + "description": "Constant C", + "type": "number" + }, + "alpha": { + "title": "Exponent constant", + "description": "Exponent constant", + "type": "number" + }, + "type": { + "title": "Type", + "default": "FossumCarrierLifetime", + "enum": [ + "FossumCarrierLifetime" + ], + "type": "string" + } + }, + "required": [ + "tau_300", + "alpha_T", + "N0", + "A", + "B", + "C", + "alpha" + ], + "additionalProperties": false + }, + "ShockleyReedHallRecombination": { + "title": "ShockleyReedHallRecombination", + "description": "Defines the parameters for the Shockley-Reed-Hall (SRH) recombination model.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntau_n : Union[PositiveFloat, FossumCarrierLifetime]\n Electron lifetime\ntau_p : Union[PositiveFloat, FossumCarrierLifetime]\n [units = sec]. Hole lifetime\n\nNotes\n-----\n\n The recombination rate parameter from this model is defined from [1]_ as follows:\n\n .. math::\n\n R_{SRH} = \\frac{n p - n_0 p_0}{\\tau_p \\left(n + \\sqrt{n_0 p_0}\\right) + \\tau_n \\left(p + \\sqrt{n_0 p_0}\\right)}.\n\n Note that the electron and holes densities are defined within the :class:`SemiconductorMedium`. The electron\n lifetime :math:`\\tau_n` and hole lifetimes :math:`\\tau_p` need to be defined.\n\n\n .. [1] Schenk. A model for the field and temperature dependence of shockley-read-hall\n lifetimes in silicon. Solid-State Electronics, 35:1585\u20131596, 1992.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6,\n ... )\n\nNote\n----\nImportant considerations when using this model:\n\n- Currently, lifetimes are considered constant (not dependent on temperature or doping).\n- This model represents mid-gap traps Shockley-Reed-Hall recombination.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "tau_n": { + "title": "Electron lifetime", + "description": "Electron lifetime", + "union": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "tau_p": { + "title": "Hole lifetime", + "description": "Hole lifetime", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/FossumCarrierLifetime" + } + ] + }, + "type": { + "title": "Type", + "default": "ShockleyReedHallRecombination", + "enum": [ + "ShockleyReedHallRecombination" + ], + "type": "string" + } + }, + "required": [ + "tau_n", + "tau_p" + ], + "additionalProperties": false + }, + "SlotboomBandGapNarrowing": { + "title": "SlotboomBandGapNarrowing", + "description": "Parameters for the Slotboom model for band-gap narrowing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nv1 : PositiveFloat\n [units = V]. $V_{1,bgn}$ parameter\nn2 : PositiveFloat\n [units = 1/cm^3]. $N_{2,bgn}$ parameter\nc2 : float\n $C_{2,bgn}$ parameter\nmin_N : NonNegativeFloat\n [units = 1/cm^3]. Bandgap narrowing is applied at location where total doping is higher than 'min_N'.\n\nNotes\n------\n The Slotboom band-gap narrowing :math:`\\Delta E_G` model is discussed in [1]_ as follows:\n\n .. math::\n\n \\Delta E_G = V_{1,bgn} \\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right)\n + \\sqrt{\\left( \\ln \\left( \\frac{N_{tot}}{N_{2,bgn}} \\right) \\right)^2 + C_{2,bgn}} \\right)\n \\quad \\text{if} \\quad N_{tot} \\geq 10^{15} \\text{cm}^{-3},\n\n \\Delta E_G = 0 \\quad \\text{if} \\quad N_{tot} < 10^{15} \\text{cm}^{-3}.\n\n Note that :math:`N_{tot}` is the total doping as defined within a :class:`SemiconductorMedium`.\n\n Example\n -------\n >>> import tidy3d as td\n >>> default_Si = td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... )\n\n .. [1] 'UNIFIED APPARENT BANDGAP NARROWING IN n- AND p-TYPE SILICON' Solid-State Electronics Vol. 35, No. 2, pp. 125-129, 1992", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "v1": { + "title": "$V_{1,bgn}$ parameter", + "description": "$V_{1,bgn}$ parameter", + "units": "V", + "exclusiveMinimum": 0, + "type": "number" + }, + "n2": { + "title": "$N_{2,bgn}$ parameter", + "description": "$N_{2,bgn}$ parameter", + "units": "1/cm^3", + "exclusiveMinimum": 0, + "type": "number" + }, + "c2": { + "title": "$C_{2,bgn}$ parameter", + "description": "$C_{2,bgn}$ parameter", + "type": "number" + }, + "min_N": { + "title": "Minimum total doping", + "description": "Bandgap narrowing is applied at location where total doping is higher than 'min_N'.", + "units": "1/cm^3", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "SlotboomBandGapNarrowing", + "enum": [ + "SlotboomBandGapNarrowing" + ], + "type": "string" + } + }, + "required": [ + "v1", + "n2", + "c2", + "min_N" + ], + "additionalProperties": false + }, + "ConstantDoping": { + "title": "ConstantDoping", + "description": "Sets constant doping :math:`N` in the specified box with a :parameter`size` and :parameter:`concentration`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nconcentration : NonNegativeFloat = 0\n [units = 1/cm^3]. Doping concentration density in #/cm^3.\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> constant_box1 = td.ConstantDoping(center=(0, 0, 0), size=(2, 2, 2), concentration=1e18)\n>>> constant_box2 = td.ConstantDoping.from_bounds(rmin=box_coords[0], rmax=box_coords[1], concentration=1e18)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConstantDoping", + "enum": [ + "ConstantDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "concentration": { + "title": "Doping concentration density.", + "description": "Doping concentration density in #/cm^3.", + "default": 0, + "units": "1/cm^3", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size" + ], + "additionalProperties": false + }, + "GaussianDoping": { + "title": "GaussianDoping", + "description": "Sets a gaussian doping in the specified box.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nref_con : PositiveFloat\n Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.\nconcentration : PositiveFloat\n The concentration at the center of the box.\nwidth : PositiveFloat\n Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. \nsource : str = xmin\n Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']\n\nFor translationally invariant behavior in one dimension, the box must have infinite size in the\nhomogenous (invariant) direction.\n\nNotes\n-----\nThe Gaussian doping concentration :math:`N` is defined in the following manner:\n\n- :math:`N=N_{\\text{max}}` at locations more than :math:``width`` um away from the sides of the box.\n- :math:`N=N_{\\text{ref}}` at location on the box sides.\n- a Gaussian variation between :math:`N_{\\text{max}}` and :math:`N_{\\text{ref}}` at locations less than ``width``\num away from the sides.\n\nBy definition, all sides of the box will have concentration :math:`N_{\\text{ref}}` (except the side specified\nas source) and the center of the box (``width`` away from the box sides) will have a concentration\n:math:`N_{\\text{max}}`.\n\n.. math::\n\n N = \\{N_{\\text{max}}\\} \\exp \\left[\n - \\ln \\left( \\frac{\\{N_{\\text{max}}\\}}{\\{N_{\\text{ref}}\\}} \\right)\n \\left( \\frac{(x|y|z) - \\{(x|y|z)_{\\text{box}}\\}}{\\text{width}} \\right)^2\n \\right]\n\nExample\n-------\n>>> import tidy3d as td\n>>> box_coords = [\n... [-1, -1, -1],\n... [1, 1, 1]\n... ]\n>>> gaussian_box1 = td.GaussianDoping(\n... center=(0, 0, 0),\n... size=(2, 2, 2),\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )\n>>> gaussian_box2 = td.GaussianDoping.from_bounds(\n... rmin=box_coords[0],\n... rmax=box_coords[1],\n... ref_con=1e15,\n... concentration=1e18,\n... width=0.1,\n... source=\"xmin\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GaussianDoping", + "enum": [ + "GaussianDoping" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "ref_con": { + "title": "Reference concentration.", + "description": "Reference concentration. This is the minimum concentration in the box and it is attained at the edges/faces of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concentration": { + "title": "Concentration", + "description": "The concentration at the center of the box.", + "exclusiveMinimum": 0, + "type": "number" + }, + "width": { + "title": "Width of the gaussian.", + "description": "Width of the gaussian. The concentration will transition from 'concentration' at the center of the box to 'ref_con' at the edge/face of the box in a distance equal to 'width'. ", + "exclusiveMinimum": 0, + "type": "number" + }, + "source": { + "title": "Source face", + "description": "Specifies the side of the box acting as the source, i.e., the face specified does not have a gaussian evolution normal to it, instead the concentration is constant from this face. Accepted values for 'source' are ['xmin', 'xmax', 'ymin', 'ymax', 'zmin', 'zmax']", + "default": "xmin", + "type": "string" + } + }, + "required": [ + "size", + "ref_con", + "concentration", + "width" + ], + "additionalProperties": false + }, + "SemiconductorMedium": { + "title": "SemiconductorMedium", + "description": "This class is used to define semiconductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for medium.\nfrequency_range : Optional[Tuple[float, float]] = None\n [units = (Hz, Hz)]. Optional range of validity for the medium.\nallow_gain : bool = False\n Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.\nnonlinear_spec : Union[NonlinearSpec, NonlinearSusceptibility] = None\n Nonlinear spec applied on top of the base medium properties.\nmodulation_spec : Optional[ModulationSpec] = None\n Modulation spec applied on top of the base medium properties.\nviz_spec : Optional[VisualizationSpec] = None\n Plotting specification for visualizing medium.\nheat_spec : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.\npermittivity : ConstrainedFloatValue = 1.0\n [units = None (relative permittivity)]. Relative permittivity.\nN_c : PositiveFloat\n [units = cm^(-3)]. $N_c$ Effective density of states in the conduction band.\nN_v : PositiveFloat\n [units = cm^(-3)]. $N_v$ Effective density of states in the valence band.\nE_g : PositiveFloat\n [units = eV]. Band-gap energy\nmobility_n : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for electrons\nmobility_p : Union[CaugheyThomasMobility, ConstantMobilityModel]\n Mobility model for holes\nR : Tuple[Union[AugerRecombination, RadiativeRecombination, ShockleyReedHallRecombination], ...] = []\n Array containing the R models to be applied to the material.\ndelta_E_g : Optional[SlotboomBandGapNarrowing] = None\n Bandgap narrowing model.\nN_a : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\nN_d : Union[NonNegativeFloat, SpatialDataArray, tuple[Union[tidy3d.components.tcad.doping.ConstantDoping, tidy3d.components.tcad.doping.GaussianDoping], ...]] = 0\n [units = 1/cm^3]. Units of 1/cm^3\n\nNotes\n-----\nSemiconductors are associated with ``Charge`` simulations. During these simulations\nthe Drift-Diffusion (DD) equations will be solved in semiconductors. In what follows, a\ndescription of the assumptions taken and its limitations is put forward.\n\nThe iso-thermal DD equations are summarized here\n\n.. math::\n\n \\begin{equation}\n - \\nabla \\cdot \\left( \\varepsilon_0 \\varepsilon_r \\nabla \\psi \\right) = q\n \\left( p - n + N_d^+ - N_a^- \\right)\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial n}{\\partial t} = \\nabla \\cdot \\mathbf{J_n} - qR\n \\end{equation}\n\n.. math::\n\n \\begin{equation}\n q \\frac{\\partial p}{\\partial t} = -\\nabla \\cdot \\mathbf{J_p} - qR\n \\end{equation}\n\nAs well as iso-thermal, the system is considered to be at :math:`T=300`. This restriction will\nbe removed in future releases.\n\nThe above system requires the definition of the flux functions (free carrier current density), :math:`\\mathbf{J_n}` and\n:math:`\\mathbf{J_p}`. We consider the usual form\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_n} = q \\mu_n \\mathbf{F_{n}} + q D_n \\nabla n\n \\end{equation}\n\n\n.. math::\n\n \\begin{equation}\n \\mathbf{J_p} = q \\mu_p \\mathbf{F_{p}} - q D_p \\nabla p\n \\end{equation}\n\n\nwhere we simplify the effective field defined in [1]_ to\n\n.. math::\n\n \\begin{equation}\n \\mathbf{F_{n,p}} = \\nabla \\psi\n \\end{equation}\n\ni.e., we are not considering the effect of band-gap narrowing and degeneracy on the effective\nelectric field :math:`\\mathbf{F_{n,p}}`. This is a good approximation for non-degenerate semiconductors.\n\nLet's explore how material properties are defined as class parameters or other classes.\n\n .. list-table::\n :widths: 25 25 75\n :header-rows: 1\n\n * - Symbol\n - Parameter Name\n - Description\n * - :math:`N_a`\n - ``N_a``\n - Ionized acceptors density\n * - :math:`N_d`\n - ``N_d``\n - Ionized donors density\n * - :math:`N_c`\n - ``N_c``\n - Effective density of states in the conduction band.\n * - :math:`N_v`\n - ``N_v``\n - Effective density of states in valence band.\n * - :math:`R`\n - ``R``\n - Generation-Recombination term.\n * - :math:`E_g`\n - ``E_g``\n - Bandgap Energy.\n * - :math:`\\Delta E_g`\n - ``delta_E_g``\n - Bandgap Narrowing.\n * - :math:`\\sigma`\n - ``conductivity``\n - Electrical conductivity.\n * - :math:`\\varepsilon_r`\n - ``permittivity``\n - Relative permittivity.\n * - :math:`q`\n - ``tidy3d.constants.Q_e``\n - Fundamental electron charge.\n\nExample\n-------\n >>> import tidy3d as td\n >>> default_Si = td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=([\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ]),\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n\n\nWarning\n-------\n Current limitations of the formulation include:\n\n - Boltzmann statistics are supported\n - Iso-thermal equations with :math:`T=300K`\n - Steady state only\n - Dopants are considered to be fully ionized\n\nNote\n----\n - Both :math:`N_a` and :math:`N_d` can be either a positive number or an ``xarray.DataArray``.\n - Default values for parameters and models are those appropriate for Silicon.\n - The current implementation is a good approximation for non-degenerate semiconductors.\n\n\n.. [1] Schroeder, D., T. Ostermann, and O. Kalz. \"Comparison of transport models far the simulation of degenerate semiconductors.\" Semiconductor science and technology 9.4 (1994): 364.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for medium.", + "type": "string" + }, + "frequency_range": { + "title": "Frequency Range", + "description": "Optional range of validity for the medium.", + "units": [ + "Hz", + "Hz" + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "allow_gain": { + "title": "Allow gain medium", + "description": "Allow the medium to be active. Caution: simulations with a gain medium are unstable, and are likely to diverge.Simulations where 'allow_gain' is set to 'True' will still be charged even if diverged. Monitor data up to the divergence point will still be returned and can be useful in some cases.", + "default": false, + "type": "boolean" + }, + "nonlinear_spec": { + "title": "Nonlinear Spec", + "description": "Nonlinear spec applied on top of the base medium properties.", + "anyOf": [ + { + "$ref": "#/definitions/NonlinearSpec" + }, + { + "$ref": "#/definitions/NonlinearSusceptibility" + } + ] + }, + "modulation_spec": { + "title": "Modulation Spec", + "description": "Modulation spec applied on top of the base medium properties.", + "allOf": [ + { + "$ref": "#/definitions/ModulationSpec" + } + ] + }, + "viz_spec": { + "title": "Visualization Specification", + "description": "Plotting specification for visualizing medium.", + "allOf": [ + { + "$ref": "#/definitions/VisualizationSpec" + } + ] + }, + "heat_spec": { + "title": "Heat Specification", + "description": "DEPRECATED: Use `td.MultiPhysicsMedium`. Specification of the medium heat properties. They are used for solving the heat equation via the ``HeatSimulation`` interface. Such simulations can beused for investigating the influence of heat propagation on the properties of optical systems. Once the temperature distribution in the system is found using ``HeatSimulation`` object, ``Simulation.perturbed_mediums_copy()`` can be used to convert mediums with perturbation models defined into spatially dependent custom mediums. Otherwise, the ``heat_spec`` does not directly affect the running of an optical ``Simulation``.", + "discriminator": { + "propertyName": "type", + "mapping": { + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "SemiconductorMedium", + "enum": [ + "SemiconductorMedium" + ], + "type": "string" + }, + "permittivity": { + "title": "Permittivity", + "description": "Relative permittivity.", + "default": 1.0, + "minimum": 1.0, + "units": "None (relative permittivity)", + "type": "number" + }, + "N_c": { + "title": "Effective density of electron states", + "description": "$N_c$ Effective density of states in the conduction band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "N_v": { + "title": "Effective density of hole states", + "description": "$N_v$ Effective density of states in the valence band.", + "units": "cm^(-3)", + "exclusiveMinimum": 0, + "type": "number" + }, + "E_g": { + "title": "Band-gap energy", + "description": "Band-gap energy", + "units": "eV", + "exclusiveMinimum": 0, + "type": "number" + }, + "mobility_n": { + "title": "Mobility model for electrons", + "description": "Mobility model for electrons", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "mobility_p": { + "title": "Mobility model for holes", + "description": "Mobility model for holes", + "anyOf": [ + { + "$ref": "#/definitions/CaugheyThomasMobility" + }, + { + "$ref": "#/definitions/ConstantMobilityModel" + } + ] + }, + "R": { + "title": "Generation-Recombination models", + "description": "Array containing the R models to be applied to the material.", + "default": [], + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/AugerRecombination" + }, + { + "$ref": "#/definitions/RadiativeRecombination" + }, + { + "$ref": "#/definitions/ShockleyReedHallRecombination" + } + ] + } + }, + "delta_E_g": { + "title": "$\\Delta E_g$ Bandgap narrowing model.", + "description": "Bandgap narrowing model.", + "allOf": [ + { + "$ref": "#/definitions/SlotboomBandGapNarrowing" + } + ] + }, + "N_a": { + "title": "Doping: Acceptor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + }, + "N_d": { + "title": "Doping: Donor concentration", + "description": "Units of 1/cm^3", + "default": 0, + "units": "1/cm^3", + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ConstantDoping" + }, + { + "$ref": "#/definitions/GaussianDoping" + } + ] + } + } + ] + } + }, + "required": [ + "N_c", + "N_v", + "E_g", + "mobility_n", + "mobility_p" + ], + "additionalProperties": false + }, + "MultiPhysicsMedium": { + "title": "MultiPhysicsMedium", + "description": "Contains multiple multi-physical properties as defined for each solver medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Medium name\noptical : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, NoneType] = None\n Specifies optical properties.\nheat : Union[FluidSpec, SolidSpec, SolidMedium, FluidMedium, NoneType] = None\n Specifies properties for Heat simulations.\ncharge : Union[ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium, NoneType] = None\n Specifies properties for Charge simulations.\n\nExamples\n--------\nFor *silica* (:math:`SiO_2`):\n >>> import tidy3d as td\n >>> SiO2 = td.MultiPhysicsMedium(\n ... optical=td.Medium(permittivity=3.9),\n ... charge=td.ChargeInsulatorMedium(permittivity=3.9), # redefining permittivity\n ... name=\"SiO2\",\n ... )\n\nFor a silicon ``MultiPhysicsMedium`` composed of an optical model\nfrom the material library and custom charge :class:`SemiconductorMedium`:\n >>> import tidy3d as td\n >>> default_multiphysics_Si = td.MultiPhysicsMedium(\n ... optical=td.material_library['cSi']['Green2008'],\n ... charge=td.SemiconductorMedium(\n ... N_c=2.86e19,\n ... N_v=3.1e19,\n ... E_g=1.11,\n ... mobility_n=td.CaugheyThomasMobility(\n ... mu_min=52.2,\n ... mu=1471.0,\n ... ref_N=9.68e16,\n ... exp_N=0.68,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... mobility_p=td.CaugheyThomasMobility(\n ... mu_min=44.9,\n ... mu=470.5,\n ... ref_N=2.23e17,\n ... exp_N=0.719,\n ... exp_1=-0.57,\n ... exp_2=-2.33,\n ... exp_3=2.4,\n ... exp_4=-0.146,\n ... ),\n ... R=[\n ... td.ShockleyReedHallRecombination(\n ... tau_n=3.3e-6,\n ... tau_p=4e-6\n ... ),\n ... td.RadiativeRecombination(\n ... r_const=1.6e-14\n ... ),\n ... td.AugerRecombination(\n ... c_n=2.8e-31,\n ... c_p=9.9e-32\n ... ),\n ... ],\n ... delta_E_g=td.SlotboomBandGapNarrowing(\n ... v1=6.92 * 1e-3,\n ... n2=1.3e17,\n ... c2=0.5,\n ... min_N=1e15,\n ... ),\n ... N_a=0,\n ... N_d=0\n ... )\n ... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Medium name", + "type": "string" + }, + "optical": { + "title": "Optical properties", + "description": "Specifies optical properties.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "heat": { + "title": "Heat properties", + "description": "Specifies properties for Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + } + ] + }, + "charge": { + "title": "Charge properties", + "description": "Specifies properties for Charge simulations.", + "anyOf": [ + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "type": { + "title": "Type", + "default": "MultiPhysicsMedium", + "enum": [ + "MultiPhysicsMedium" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Structure": { + "title": "Structure", + "description": "Defines a physical object that interacts with the electromagnetic fields.\nA :class:`Structure` is a combination of a material property (:class:`AbstractMedium`)\nand a :class:`Geometry`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : Optional[int] = None\n Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium]\n Defines the electromagnetic properties of the structure's medium.\n\nNotes\n------\n\n Structures can indeed be larger than the simulation domain in ``tidy3d``. In such cases, ``tidy3d`` will\n automatically truncate the geometry that goes beyond the domain boundaries. For best results, structures that\n intersect with absorbing boundaries or simulation edges should extend all the way through. In many such\n cases, an \u201cinfinite\u201d size :class:`td.inf` can be used to define the size along that dimension.\n\nExample\n-------\n>>> from tidy3d import Box, Medium\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> glass = Medium(permittivity=3.9)\n>>> struct = Structure(geometry=box, medium=glass, name='glass_box')\n\nSee Also\n--------\n\n**Notebooks:**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n* `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n* `Visualizing geometries in Tidy3D <../../notebooks/VizSimulation.html>`_\n\n**Lectures:**\n\n* `Using FDTD to Compute a Transmission Spectrum `_\n\n**GUI:**\n\n* `Structures `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in structure overlapping region. The material property in the overlapping region is dictated by the structure of higher priority. For structures of equal priority, the structure added later to the structure list takes precedence. When `priority` is None, the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + "type": "integer" + }, + "type": { + "title": "Type", + "default": "Structure", + "enum": [ + "Structure" + ], + "type": "string" + }, + "medium": { + "title": "Medium", + "description": "Defines the electromagnetic properties of the structure's medium.", + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + } + }, + "required": [ + "geometry", + "medium" + ], + "additionalProperties": false + }, + "GaussianPulse": { + "title": "GaussianPulse", + "description": "Source time dependence that describes a Gaussian pulse.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : ConstrainedFloatValue = 5.0\n Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).\nremove_dc_component : bool = True\n Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.\n\nExample\n-------\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "GaussianPulse", + "enum": [ + "GaussianPulse" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).", + "default": 5.0, + "minimum": 2.5, + "type": "number" + }, + "remove_dc_component": { + "title": "Remove DC Component", + "description": "Whether to remove the DC component in the Gaussian pulse spectrum. If ``True``, the Gaussian pulse is modified at low frequencies to zero out the DC component, which is usually desirable so that the fields will decay. However, for broadband simulations, it may be better to have non-vanishing source power near zero frequency. Setting this to ``False`` results in an unmodified Gaussian pulse spectrum which can have a nonzero DC component.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "freq0", + "fwidth" + ], + "additionalProperties": false + }, + "ContinuousWave": { + "title": "ContinuousWave", + "description": "Source time dependence that ramps up to continuous oscillation\nand holds until end of simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : ConstrainedFloatValue = 5.0\n Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).\n\nNote\n----\nField decay will not occur, so the simulation will run for the full ``run_time``.\nAlso, source normalization of frequency-domain monitors is not meaningful.\n\nExample\n-------\n>>> cw = ContinuousWave(freq0=200e12, fwidth=20e12)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "ContinuousWave", + "enum": [ + "ContinuousWave" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the maximum value of the pulse in units of 1 / (``2pi * fwidth``).", + "default": 5.0, + "minimum": 2.5, + "type": "number" + } + }, + "required": [ + "freq0", + "fwidth" + ], + "additionalProperties": false + }, + "TimeDataset": { + "title": "TimeDataset", + "description": "Dataset for storing a function of time.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nvalues : TimeDataArray\n Values as a function of time.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TimeDataset", + "enum": [ + "TimeDataset" + ], + "type": "string" + }, + "values": { + "title": "DataArray", + "description": "Values as a function of time.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "required": [ + "values" + ], + "additionalProperties": false + }, + "CustomSourceTime": { + "title": "CustomSourceTime", + "description": "Custom source time dependence consisting of a real or complex envelope\nmodulated at a central frequency, as shown below.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\namplitude : NonNegativeFloat = 1.0\n Real-valued maximum amplitude of the time dependence.\nphase : float = 0.0\n [units = rad]. Phase shift of the time dependence.\nfreq0 : PositiveFloat\n [units = Hz]. Central frequency of the pulse.\nfwidth : PositiveFloat\n [units = Hz]. Standard deviation of the frequency content of the pulse.\noffset : float = 0.0\n Time delay of the envelope in units of 1 / (``2pi * fwidth``).\nsource_time_dataset : Optional[TimeDataset]\n Dataset for storing the envelope of the custom source time. This envelope will be modulated by a complex exponential at frequency ``freq0``.\n\nNote\n----\n.. math::\n\n amp\\_time(t) = amplitude \\cdot \\\n e^{i \\cdot phase - 2 \\pi i \\cdot freq0 \\cdot t} \\cdot \\\n envelope(t - offset / (2 \\pi \\cdot fwidth))\n\nNote\n----\nDepending on the envelope, field decay may not occur.\nIf field decay does not occur, then the simulation will run for the full ``run_time``.\nAlso, if field decay does not occur, then source normalization of frequency-domain\nmonitors is not meaningful.\n\nNote\n----\nThe source time dependence is linearly interpolated to the simulation time steps.\nThe sampling rate should be sufficiently fast that this interpolation does not\nintroduce artifacts. The source time dependence should also start at zero and ramp up smoothly.\nThe first and last values of the envelope will be used for times that are out of range\nof the provided data.\n\nExample\n-------\n>>> cst = CustomSourceTime.from_values(freq0=1, fwidth=0.1,\n... values=np.linspace(0, 9, 10), dt=0.1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "amplitude": { + "title": "Amplitude", + "description": "Real-valued maximum amplitude of the time dependence.", + "default": 1.0, + "minimum": 0, + "type": "number" + }, + "phase": { + "title": "Phase", + "description": "Phase shift of the time dependence.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "type": { + "title": "Type", + "default": "CustomSourceTime", + "enum": [ + "CustomSourceTime" + ], + "type": "string" + }, + "freq0": { + "title": "Central Frequency", + "description": "Central frequency of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "fwidth": { + "title": "Fwidth", + "description": "Standard deviation of the frequency content of the pulse.", + "units": "Hz", + "exclusiveMinimum": 0, + "type": "number" + }, + "offset": { + "title": "Offset", + "description": "Time delay of the envelope in units of 1 / (``2pi * fwidth``).", + "default": 0.0, + "type": "number" + }, + "source_time_dataset": { + "title": "Source time dataset", + "description": "Dataset for storing the envelope of the custom source time. This envelope will be modulated by a complex exponential at frequency ``freq0``.", + "allOf": [ + { + "$ref": "#/definitions/TimeDataset" + } + ] + } + }, + "required": [ + "freq0", + "fwidth", + "source_time_dataset" + ], + "additionalProperties": false + }, + "UniformCurrentSource": { + "title": "UniformCurrentSource", + "description": "Source in a rectangular volume with uniform time dependence.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\ninterpolate : bool = True\n Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.\nconfine_to_bounds : bool = False\n If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.\npolarization : Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Specifies the direction and type of current component.\n\nNotes\n-----\n\n Inputting the parameter ``size=(0,0,0)`` defines the equivalent of a point source.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> pt_source = UniformCurrentSource(size=(0,0,0), source_time=pulse, polarization='Ex')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "UniformCurrentSource", + "enum": [ + "UniformCurrentSource" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "interpolate": { + "title": "Enable Interpolation", + "description": "Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.", + "default": true, + "type": "boolean" + }, + "confine_to_bounds": { + "title": "Confine to Analytical Bounds", + "description": "If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.", + "default": false, + "type": "boolean" + }, + "polarization": { + "title": "Polarization", + "description": "Specifies the direction and type of current component.", + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "required": [ + "size", + "source_time", + "polarization" + ], + "additionalProperties": false + }, + "PointDipole": { + "title": "PointDipole", + "description": "Uniform current source with a zero size. The source corresponds to an infinitesimal antenna\nwith a fixed current density, and is slightly different from a related definition that is used\nin some contexts, namely an oscillating electric or magnetic dipole. The two are related through\na factor of ``omega ** 2`` in the power normalization, where ``omega`` is the angular frequency\nof the oscillation. This is discussed further in our\n`source normalization <../../faq/docs/faq/How-are-results-normalized.html>`_ FAQ page.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Tuple[Literal[0], Literal[0], Literal[0]] = (0, 0, 0)\n [units = um]. Size in x, y, and z directions, constrained to ``(0, 0, 0)``.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\ninterpolate : bool = True\n Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.\nconfine_to_bounds : bool = False\n If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.\npolarization : Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Specifies the direction and type of current component.\n\n..\n TODO add image of how it looks like based on sim 1.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> pt_dipole = PointDipole(center=(1,2,3), source_time=pulse, polarization='Ex')\n\nSee Also\n--------\n\n**Notebooks**\n * `Particle swarm optimization of quantum emitter light extraction to free space <../../notebooks/BullseyeCavityPSO.html>`_\n * `Adjoint optimization of quantum emitter light extraction to an integrated waveguide <../../notebooks/AdjointPlugin12LightExtractor.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PointDipole", + "enum": [ + "PointDipole" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions, constrained to ``(0, 0, 0)``.", + "default": [ + 0, + 0, + 0 + ], + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0 + ], + "type": "integer" + }, + { + "enum": [ + 0 + ], + "type": "integer" + }, + { + "enum": [ + 0 + ], + "type": "integer" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "interpolate": { + "title": "Enable Interpolation", + "description": "Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.", + "default": true, + "type": "boolean" + }, + "confine_to_bounds": { + "title": "Confine to Analytical Bounds", + "description": "If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.", + "default": false, + "type": "boolean" + }, + "polarization": { + "title": "Polarization", + "description": "Specifies the direction and type of current component.", + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "required": [ + "source_time", + "polarization" + ], + "additionalProperties": false + }, + "GaussianBeam": { + "title": "GaussianBeam", + "description": "Gaussian distribution on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_radius : PositiveFloat = 1.0\n [units = um]. Radius of the beam at the waist.\nwaist_distance : float = 0.0\n [units = um]. Distance from the beam waist along the propagation direction. A positive value means the waist is positioned behind the source, considering the propagation direction. For example, for a beam propagating in the ``+`` direction, a positive value of ``beam_distance`` means the beam waist is positioned in the ``-`` direction (behind the source). A negative value means the beam waist is in the ``+`` direction (in front of the source). For an angled source, the distance is defined along the rotated propagation direction.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = GaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_radius=1.0)\n\nNotes\n--------\nIf one wants the focus 'in front' of the source, a negative value of ``beam_distance`` is needed.\n\n.. image:: ../../_static/img/beam_waist.png\n :width: 30%\n :align: center\n\nSee Also\n--------\n\n**Notebooks**:\n * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "GaussianBeam", + "enum": [ + "GaussianBeam" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "pol_angle": { + "title": "Polarization Angle", + "description": "Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.", + "default": 0, + "units": "rad", + "type": "number" + }, + "waist_radius": { + "title": "Waist Radius", + "description": "Radius of the beam at the waist.", + "default": 1.0, + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "waist_distance": { + "title": "Waist Distance", + "description": "Distance from the beam waist along the propagation direction. A positive value means the waist is positioned behind the source, considering the propagation direction. For example, for a beam propagating in the ``+`` direction, a positive value of ``beam_distance`` means the beam waist is positioned in the ``-`` direction (behind the source). A negative value means the beam waist is in the ``+`` direction (in front of the source). For an angled source, the distance is defined along the rotated propagation direction.", + "default": 0.0, + "units": "um", + "type": "number" + } + }, + "required": [ + "size", + "source_time", + "direction" + ], + "additionalProperties": false + }, + "AstigmaticGaussianBeam": { + "title": "AstigmaticGaussianBeam", + "description": "The simple astigmatic Gaussian distribution allows\nboth an elliptical intensity profile and different waist locations for the two principal axes\nof the ellipse. When equal waist sizes and equal waist distances are specified in the two\ndirections, this source becomes equivalent to :class:`GaussianBeam`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nwaist_sizes : Tuple[PositiveFloat, PositiveFloat] = (1.0, 1.0)\n [units = um]. Size of the beam at the waist in the local x and y directions.\nwaist_distances : Tuple[float, float] = (0.0, 0.0)\n [units = um]. Distance to the beam waist along the propagation direction for the waist sizes in the local x and y directions. When ``direction`` is ``+`` and ``waist_distances`` are positive, the waist is on the ``-`` side (behind) the source plane. When ``direction`` is ``+`` and ``waist_distances`` are negative, the waist is on the ``+`` side (in front) of the source plane.\n\nNotes\n-----\n\n This class implements the simple astigmatic Gaussian beam described in _`[1]`.\n\n **References**:\n\n .. [1] Kochkina et al., Applied Optics, vol. 52, issue 24, 2013.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> gauss = AstigmaticGaussianBeam(\n... size=(0,3,3),\n... source_time=pulse,\n... pol_angle=np.pi / 2,\n... direction='+',\n... waist_sizes=(1.0, 2.0),\n... waist_distances = (3.0, 4.0))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "AstigmaticGaussianBeam", + "enum": [ + "AstigmaticGaussianBeam" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. For broadband, angled Gaussian beams it is advisable to check the beam propagation in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "pol_angle": { + "title": "Polarization Angle", + "description": "Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.", + "default": 0, + "units": "rad", + "type": "number" + }, + "waist_sizes": { + "title": "Waist sizes", + "description": "Size of the beam at the waist in the local x and y directions.", + "default": [ + 1.0, + 1.0 + ], + "units": "um", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + }, + "waist_distances": { + "title": "Waist distances", + "description": "Distance to the beam waist along the propagation direction for the waist sizes in the local x and y directions. When ``direction`` is ``+`` and ``waist_distances`` are positive, the waist is on the ``-`` side (behind) the source plane. When ``direction`` is ``+`` and ``waist_distances`` are negative, the waist is on the ``+`` side (in front) of the source plane.", + "default": [ + 0.0, + 0.0 + ], + "units": "um", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number" + }, + { + "type": "number" + } + ] + } + }, + "required": [ + "size", + "source_time", + "direction" + ], + "additionalProperties": false + }, + "ModeSpec": { + "title": "ModeSpec", + "description": "Stores specifications for the mode solver to find an electromagntic mode.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\nprecision : Literal['auto', 'single', 'double'] = double\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = central\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.\n\nNotes\n-----\n\n The :attr:`angle_theta` and :attr:`angle_phi` parameters define the injection axis as illustrated in the figure\n below, with respect to the axis normal to the mode plane (``x`` in the figure). Note that :attr:`angle_theta`\n must be smaller than :math:`\\frac{pi}{2}`. To inject in the backward direction, we can still use the\n ``direction`` parameter as also shown in the figure. Similarly, the mode amplitudes computed in mode monitors\n are defined w.r.t. the ``forward`` and ``backward`` directions as illustrated. Note, the planar axes are\n found by popping the injection axis from ``{x,y,z}``. For example, if injection axis is ``y``, the planar\n axes are ordered ``{x,z}``.\n\n .. image:: ../../notebooks/img/ring_modes.png\n\n The :attr:`bend_axis` is the axis normal to the plane in which the bend lies, (``z`` in the diagram below). In\n the mode specification, it is defined locally for the mode plane as one of the two axes tangential to the\n plane. In the case of bends that lie in the ``xy``-plane, the mode plane would be either in ``xz`` or in\n ``yz``, so in both cases the correct setting is ``bend_axis=1``, selecting the global ``z``. The\n ``bend_radius`` is counted from the center of the mode plane to the center of the curvature,\n along the tangential axis perpendicular to the bend axis. This radius can also be negative, if the center of\n the mode plane is smaller than the center of the bend.\n\n .. image:: ../../notebooks/img/mode_angled.png\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3, target_neff=1.5)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Introduction on tidy3d working principles <../../notebooks/Primer.html#Modes>`_\n * `Defining mode sources and monitors <../../notebooks/ModalSourcesMonitors.html>`_\n * `Injecting modes in bent and angled waveguides <../../notebooks/ModesBentAngled.html>`_\n * `Waveguide to ring coupling <../../notebooks/WaveguideToRingCoupling.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_modes": { + "title": "Number of modes", + "description": "Number of modes returned by mode solver.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "target_neff": { + "title": "Target effective index", + "description": "Guess for effective index of the mode.", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_pml": { + "title": "Number of PML layers", + "description": "Number of standard pml layers to add in the two tangential axes.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ] + }, + "filter_pol": { + "title": "Polarization filtering", + "description": "The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.", + "enum": [ + "te", + "tm" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "precision": { + "title": "single, double, or automatic precision in mode solver", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "double", + "enum": [ + "auto", + "single", + "double" + ], + "type": "string" + }, + "bend_radius": { + "title": "Bend radius", + "description": "A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.", + "units": "um", + "type": "number" + }, + "bend_axis": { + "title": "Bend axis", + "description": "Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).", + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "angle_rotation": { + "title": "Use fields rotation when angle_theta is not zero", + "description": "Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.", + "default": false, + "type": "boolean" + }, + "track_freq": { + "title": "Mode Tracking Frequency", + "description": "Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed.", + "default": "central", + "enum": [ + "central", + "lowest", + "highest" + ], + "type": "string" + }, + "group_index_step": { + "title": "Frequency step for group index computation", + "description": "Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "default": false, + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "boolean" + } + ] + }, + "type": { + "title": "Type", + "default": "ModeSpec", + "enum": [ + "ModeSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ModeSource": { + "title": "ModeSource", + "description": "Injects current source to excite modal profile on finite extent plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nmode_index : NonNegativeInt = 0\n Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.\n\nNotes\n-----\n\n Using this mode source, it is possible selectively excite one of the guided modes of a waveguide. This can be\n computed in our eigenmode solver :class:`tidy3d.plugins.mode.ModeSolver` and implement the mode simulation in\n FDTD.\n\n Mode sources are normalized to inject exactly 1W of power at the central frequency.\n\n The modal source allows you to do directional excitation. Illustrated\n by the image below, the field is perfectly launched to the right of the source and there's zero field to the\n left of the source. Now you can contrast the behavior of the modal source with that of a dipole source. If\n you just put a dipole into the waveguide, well, you see quite a bit different in the field distribution.\n First of all, the dipole source is not directional launching. It launches waves in both directions. The\n second is that the polarization of the dipole is set to selectively excite a TE mode. But it takes some\n propagation distance before the mode settles into a perfect TE mode profile. During this process,\n there is radiation into the substrate.\n\n .. image:: ../../_static/img/mode_vs_dipole_source.png\n\n .. TODO improve links to other APIs functionality here.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> mode_spec = ModeSpec(target_neff=2.)\n>>> mode_source = ModeSource(\n... size=(10,10,0),\n... source_time=pulse,\n... mode_spec=mode_spec,\n... mode_index=1,\n... direction='-')\n\nSee Also\n--------\n\n:class:`tidy3d.plugins.mode.ModeSolver`:\n Interface for solving electromagnetic eigenmodes in a 2D plane with translational invariance in the third dimension.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `90 degree optical hybrid <../../notebooks/90OpticalHybrid.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "ModeSource", + "enum": [ + "ModeSource" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "mode_index": { + "title": "Mode Index", + "description": "Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.", + "default": 0, + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "size", + "source_time", + "direction" + ], + "additionalProperties": false + }, + "FixedInPlaneKSpec": { + "title": "FixedInPlaneKSpec", + "description": "Plane wave is injected such that its in-plane wavevector is constant. That is,\nthe injected field satisfies Bloch boundary conditions and its propagation direction is\nfrequency dependent.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FixedInPlaneKSpec", + "enum": [ + "FixedInPlaneKSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FixedAngleSpec": { + "title": "FixedAngleSpec", + "description": "Plane wave is injected such that its propagation direction is frequency independent.\nWhen using this option boundary conditions in tangential directions must be set to periodic.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FixedAngleSpec", + "enum": [ + "FixedAngleSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PlaneWave": { + "title": "PlaneWave", + "description": "Uniform current distribution on an infinite extent plane. One element of size must be zero.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 3\n Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband plane waves. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\nangular_spec : Union[FixedInPlaneKSpec, FixedAngleSpec] = FixedInPlaneKSpec(attrs={}, type='FixedInPlaneKSpec')\n Specification of plane wave propagation direction dependence on wavelength.\n\nNotes\n-----\n\n For oblique incidence, there are two possible settings: fixed in-plane k-vector and fixed-angle mode.\n The first requires Bloch periodic boundary conditions, and the incidence angle is exact only at the central wavelength.\n The latter requires periodic boundary conditions and maintains a constant propagation angle over a broadband spectrum.\n For more information and important notes, see this example: `Broadband PlaneWave With Constant Oblique Incident Angle `_.\n\nExample\n-------\n>>> from tidy3d import GaussianPulse\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> pw_source = PlaneWave(size=(inf,0,inf), source_time=pulse, pol_angle=0.1, direction='+')\n\nSee Also\n--------\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PlaneWave", + "enum": [ + "PlaneWave" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. Default is 3, which should cover even very broadband plane waves. For simulations which are not very broadband and the source is very large (e.g. metalens simulations), decreasing the value to 1 may lead to a speed up in the preprocessing.", + "default": 3, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "pol_angle": { + "title": "Polarization Angle", + "description": "Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.", + "default": 0, + "units": "rad", + "type": "number" + }, + "angular_spec": { + "title": "Angular Dependence Specification", + "description": "Specification of plane wave propagation direction dependence on wavelength.", + "default": { + "attrs": {}, + "type": "FixedInPlaneKSpec" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "FixedInPlaneKSpec": "#/definitions/FixedInPlaneKSpec", + "FixedAngleSpec": "#/definitions/FixedAngleSpec" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FixedInPlaneKSpec" + }, + { + "$ref": "#/definitions/FixedAngleSpec" + } + ] + } + }, + "required": [ + "size", + "source_time", + "direction" + ], + "additionalProperties": false + }, + "FieldDataset": { + "title": "FieldDataset", + "description": "Dataset storing a collection of the scalar components of E and H fields in the freq. domain\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nEx : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the x-component of the electric field.\nEy : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the y-component of the electric field.\nEz : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the z-component of the electric field.\nHx : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the x-component of the magnetic field.\nHy : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the y-component of the magnetic field.\nHz : Optional[ScalarFieldDataArray] = None\n Spatial distribution of the z-component of the magnetic field.\n\nExample\n-------\n>>> x = [-1,1]\n>>> y = [-2,0,2]\n>>> z = [-3,-1,1,3]\n>>> f = [2e14, 3e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> scalar_field = ScalarFieldDataArray((1+1j) * np.random.random((2,3,4,2)), coords=coords)\n>>> data = FieldDataset(Ex=scalar_field, Hz=scalar_field)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldDataset", + "enum": [ + "FieldDataset" + ], + "type": "string" + }, + "Ex": { + "title": "DataArray", + "description": "Spatial distribution of the x-component of the electric field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "Ey": { + "title": "DataArray", + "description": "Spatial distribution of the y-component of the electric field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "Ez": { + "title": "DataArray", + "description": "Spatial distribution of the z-component of the electric field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "Hx": { + "title": "DataArray", + "description": "Spatial distribution of the x-component of the magnetic field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "Hy": { + "title": "DataArray", + "description": "Spatial distribution of the y-component of the magnetic field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + }, + "Hz": { + "title": "DataArray", + "description": "Spatial distribution of the z-component of the magnetic field.", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + }, + "additionalProperties": false + }, + "CustomFieldSource": { + "title": "CustomFieldSource", + "description": "Implements a source corresponding to an input dataset containing ``E`` and ``H`` fields,\nusing the equivalence principle to define the actual injected currents.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nfield_dataset : Optional[FieldDataset]\n :class:`.FieldDataset` containing the desired frequency-domain fields patterns to inject. At least one tangential field component must be specified.\n\n Notes\n -----\n\n For the injection to work as expected (i.e. to reproduce the required ``E`` and ``H`` fields),\n the field data must decay by the edges of the source plane, or the source plane must span the entire\n simulation domain and the fields must match the simulation boundary conditions.\n\n The equivalent source currents are fully defined by the field components tangential to the\n source plane. For e.g. source normal along ``z``, the normal components (``Ez`` and ``Hz``)\n can be provided but will have no effect on the results, and at least one of the tangential\n components has to be in the dataset, i.e. at least one of ``Ex``, ``Ey``, ``Hx``, and ``Hy``.\n\n .. TODO add image here\n\n ..\n TODO is this generic? Only the field components tangential to the custom source plane are needed and used\n in the simulation. Due to the equivalence principle, these fully define the currents that need to be\n injected. This is not to say that the normal components of the data (:math:`E_x`, :math:`H_x` in our example)\n is lost or not injected. It is merely not needed as it can be uniquely obtained using the tangential components.\n\n ..\n TODO add example for this standalone\n Source data can be imported from file just as shown here, after the data is imported as a numpy array using\n standard numpy functions like loadtxt.\n\n If the data is not coming from a ``tidy3d`` simulation, the normalization is likely going to be arbitrary and\n the directionality of the source will likely not be perfect, even if both the ``E`` and ``H`` fields are\n provided. An empty normalizing run may be needed to accurately normalize results.\n\n To create this empty simulation it is recommended that users create a simulation with no structures but just a flux\n monitor (``tidy3D.FluxMonitor``) next to the custom source, ensuring that the flux monitor is at least one grid cell\n away from the source. Moreover, for accurate normalization, users must ensure that the same grid is used to run\n the original simulation as well as the empty simulation. The total flux calculated at the flux monitor of the empty\n simulation can then be used for proper normalization of results after ``tidy3d`` simulation.\n\n The coordinates of all provided fields are assumed to be relative to the source center.\n If only the ``E`` or only the ``H`` fields are provided, the source will not be directional,\n but will inject equal power in both directions instead.\n\nExample\n-------\n>>> from tidy3d import ScalarFieldDataArray, GaussianPulse\n>>> import tidy3d as td\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> x = np.linspace(-1, 1, 101)\n>>> y = np.linspace(-1, 1, 101)\n>>> z = np.array([0])\n>>> f = [2e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> scalar_field = ScalarFieldDataArray(np.ones((101, 101, 1, 1)), coords=coords)\n>>> dataset = FieldDataset(Ex=scalar_field)\n>>> custom_source = CustomFieldSource(\n... center=(1, 1, 1),\n... size=(2, 2, 0),\n... source_time=pulse,\n... field_dataset=dataset)\n\nCreating an empty simulation with no structures with ``FluxMonitor`` for normalization but with the same grid as the\noriginal simulation.\n\nExample\n-------\n>>> Flux_monitor = td.FluxMonitor(\n... center=(0, 0, 0),\n... size=(3, 3, 3),\n... freqs=f,\n... name=\"Flux\",\n... )\n>>> sim = td.Simulation(\n... center=[0,0,0],\n... size=(4, 4, 4),\n... structures=[],\n... sources=[custom_source],\n... monitors=[],\n... run_time = 1e-6,\n... shutoff=1e-6,\n... )\n>>> sim_empty = sim.updated_copy(monitors = [Flux_monitor], # doctest: +SKIP\n... structures = [],\n... grid_spec= sim.grid_spec.updated_copy(override_structures = sim.structures)\n... )\n\nSee Also\n--------\n\n**Notebooks**\n * `Defining spatially-varying sources <../../notebooks/CustomFieldSource.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "CustomFieldSource", + "enum": [ + "CustomFieldSource" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "field_dataset": { + "title": "Field Dataset", + "description": ":class:`.FieldDataset` containing the desired frequency-domain fields patterns to inject. At least one tangential field component must be specified.", + "allOf": [ + { + "$ref": "#/definitions/FieldDataset" + } + ] + } + }, + "required": [ + "size", + "source_time", + "field_dataset" + ], + "additionalProperties": false + }, + "CustomCurrentSource": { + "title": "CustomCurrentSource", + "description": "Implements a source corresponding to an input dataset containing ``E`` and ``H`` fields.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\ninterpolate : bool = True\n Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.\nconfine_to_bounds : bool = False\n If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.\ncurrent_dataset : Optional[FieldDataset]\n :class:`.FieldDataset` containing the desired frequency-domain electric and magnetic current patterns to inject.\n\nNotes\n-----\n\n Injects the specified components of the ``E`` and ``H`` dataset directly as ``J`` and ``M`` current\n distributions in the FDTD solver. The coordinates of all provided fields are assumed to be relative to the\n source center.\n\n The syntax is very similar to :class:`CustomFieldSource`, except instead of a ``field_dataset``, the source\n accepts a :attr:`current_dataset`. This dataset still contains :math:`E_{x,y,z}` and :math:`H_{x,y,\n z}` field components, which correspond to :math:`J` and :math:`M` components respectively. There are also\n fewer constraints on the data requirements for :class:`CustomCurrentSource`. It can be volumetric or planar\n without requiring tangential components. Finally, note that the dataset is still defined w.r.t. the source\n center, just as in the case of the :class:`CustomFieldSource`, and can then be placed anywhere in the simulation.\n\nExample\n-------\n>>> from tidy3d import ScalarFieldDataArray, GaussianPulse\n>>> import numpy as np\n>>> pulse = GaussianPulse(freq0=200e12, fwidth=20e12)\n>>> x = np.linspace(-1, 1, 101)\n>>> y = np.linspace(-1, 1, 101)\n>>> z = np.array([0])\n>>> f = [2e14]\n>>> coords = dict(x=x, y=y, z=z, f=f)\n>>> scalar_field = ScalarFieldDataArray(np.ones((101, 101, 1, 1)), coords=coords)\n>>> dataset = FieldDataset(Ex=scalar_field)\n>>> custom_source = CustomCurrentSource(\n... center=(1, 1, 1),\n... size=(2, 2, 0),\n... source_time=pulse,\n... current_dataset=dataset)\n\nSee Also\n--------\n\n**Notebooks**\n * `Defining spatially-varying sources <../../notebooks/CustomFieldSource.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "CustomCurrentSource", + "enum": [ + "CustomCurrentSource" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "interpolate": { + "title": "Enable Interpolation", + "description": "Handles reverse-interpolation of zero-size dimensions of the source. If ``False``, the source data is snapped to the nearest Yee grid point. If ``True``, equivalent source data is applied on the surrounding Yee grid points to emulate placement at the specified location using linear interpolation.", + "default": true, + "type": "boolean" + }, + "confine_to_bounds": { + "title": "Confine to Analytical Bounds", + "description": "If ``True``, any source amplitudes which, after discretization, fall beyond the bounding box of the source are zeroed out, but only along directions where the source has a non-zero extent. The bounding box is inclusive. Should be set ```True`` when the current source is being used to excite a current in a conductive material.", + "default": false, + "type": "boolean" + }, + "current_dataset": { + "title": "Current Dataset", + "description": ":class:`.FieldDataset` containing the desired frequency-domain electric and magnetic current patterns to inject.", + "allOf": [ + { + "$ref": "#/definitions/FieldDataset" + } + ] + } + }, + "required": [ + "size", + "source_time", + "current_dataset" + ], + "additionalProperties": false + }, + "TFSF": { + "title": "TFSF", + "description": "Total-field scattered-field (TFSF) source that can inject a plane wave in a finite region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsource_time : Union[GaussianPulse, ContinuousWave, CustomSourceTime]\n Specification of the source time-dependence.\nnum_freqs : ConstrainedIntValue = 1\n Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.\ndirection : Literal['+', '-']\n Specifies propagation in the positive or negative direction of the injection axis.\nangle_theta : float = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis.\nangle_phi : float = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.\npol_angle : float = 0\n [units = rad]. Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.\ninjection_axis : Literal[0, 1, 2]\n Specifies the injection axis. The plane of incidence is defined via this ``injection_axis`` and the ``direction``. The popagation axis is defined with respect to the ``injection_axis`` by ``angle_theta`` and ``angle_phi``.\n\nNotes\n-----\n\n The TFSF source injects :math:`1 W` of power per :math:`\\mu m^2` of source area along the :attr:`injection_axis`.\n Hence, the normalization for the incident field is :math:`|E_0|^2 = \\frac{2}{c\\epsilon_0}`, for any source size.\n Note that in the case of angled incidence, the same power is injected along the source's :attr:`injection_axis`,\n and not the propagation direction. This allows computing scattering and absorption cross-sections\n without the need for additional normalization.\n\n The TFSF source allows specifying a box region into which a plane wave is injected. Fields inside this region\n can be interpreted as the superposition of the incident field and the scattered field due to any scatterers\n present in the simulation domain. The fields at the edges of the TFSF box are modified at each time step such\n that the incident field is cancelled out, so that all fields outside the TFSF box are scattered fields only.\n This is useful in scenarios where one is interested in computing scattered fields only, for example when\n computing scattered cross-sections of various objects.\n\n It is important to note that when a non-uniform grid is used in the directions transverse to the\n :attr:`injection_axis` of the TFSF source, the suppression of the incident field outside the TFSF box may not be as\n close to zero as in the case of a uniform grid. Because of this, a warning may be issued when nonuniform grid\n TFSF setup is detected. In some cases, however, the accuracy may be only weakly affected, and the warnings\n can be ignored.\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Nanoparticle Scattering <../../notebooks/PlasmonicNanoparticle.html>`_: To force a uniform grid in the TFSF region and avoid the warnings, a mesh override structure can be used as illustrated here.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "TFSF", + "enum": [ + "TFSF" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "source_time": { + "title": "Source Time", + "description": "Specification of the source time-dependence.", + "discriminator": { + "propertyName": "type", + "mapping": { + "GaussianPulse": "#/definitions/GaussianPulse", + "ContinuousWave": "#/definitions/ContinuousWave", + "CustomSourceTime": "#/definitions/CustomSourceTime" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GaussianPulse" + }, + { + "$ref": "#/definitions/ContinuousWave" + }, + { + "$ref": "#/definitions/CustomSourceTime" + } + ] + }, + "num_freqs": { + "title": "Number of Frequency Points", + "description": "Number of points used to approximate the frequency dependence of the injected field. A Chebyshev interpolation is used, thus, only a small number of points is typically sufficient to obtain converged results. Note that larger values of 'num_freqs' could spread out the source time signal and introduce numerical noise, or prevent timely field decay.", + "default": 1, + "minimum": 1, + "maximum": 20, + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "Specifies propagation in the positive or negative direction of the injection axis.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis.", + "default": 0.0, + "units": "rad", + "type": "number" + }, + "pol_angle": { + "title": "Polarization Angle", + "description": "Specifies the angle between the electric field polarization of the source and the plane defined by the injection axis and the propagation axis (rad). ``pol_angle=0`` (default) specifies P polarization, while ``pol_angle=np.pi/2`` specifies S polarization. At normal incidence when S and P are undefined, ``pol_angle=0`` defines: - ``Ey`` polarization for propagation along ``x``.- ``Ex`` polarization for propagation along ``y``.- ``Ex`` polarization for propagation along ``z``.", + "default": 0, + "units": "rad", + "type": "number" + }, + "injection_axis": { + "title": "Injection Axis", + "description": "Specifies the injection axis. The plane of incidence is defined via this ``injection_axis`` and the ``direction``. The popagation axis is defined with respect to the ``injection_axis`` by ``angle_theta`` and ``angle_phi``.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + } + }, + "required": [ + "size", + "source_time", + "direction", + "injection_axis" + ], + "additionalProperties": false + }, + "Periodic": { + "title": "Periodic", + "description": "Periodic boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Periodic", + "enum": [ + "Periodic" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECBoundary": { + "title": "PECBoundary", + "description": "Perfect electric conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PECBoundary", + "enum": [ + "PECBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMCBoundary": { + "title": "PMCBoundary", + "description": "Perfect magnetic conductor boundary condition class.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PMCBoundary", + "enum": [ + "PMCBoundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PMLParams": { + "title": "PMLParams", + "description": "Specifies full set of parameters needed for complex, frequency-shifted PML.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\nkappa_order : NonNegativeInt = 3\n Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).\nkappa_min : NonNegativeFloat = 0.0\n \nkappa_max : NonNegativeFloat = 1.5\n \nalpha_order : NonNegativeInt = 3\n Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).\nalpha_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the PML alpha.\nalpha_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the PML alpha.\n\nExample\n-------\n>>> params = PMLParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5, kappa_min=0.0)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "PMLParams", + "enum": [ + "PMLParams" + ], + "type": "string" + }, + "kappa_order": { + "title": "Kappa Order", + "description": "Order of the polynomial describing the PML kappa profile (kappa~dist^kappa_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "kappa_min": { + "title": "Kappa Minimum", + "default": 0.0, + "minimum": 0, + "type": "number" + }, + "kappa_max": { + "title": "Kappa Maximum", + "default": 1.5, + "minimum": 0, + "type": "number" + }, + "alpha_order": { + "title": "Alpha Order", + "description": "Order of the polynomial describing the PML alpha profile (alpha~dist^alpha_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "alpha_min": { + "title": "Alpha Minimum", + "description": "Minimum value of the PML alpha.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "alpha_max": { + "title": "Alpha Maximum", + "description": "Maximum value of the PML alpha.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + } + }, + "additionalProperties": false + }, + "PML": { + "title": "PML", + "description": "Specifies a standard PML along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 12\n Number of layers of standard PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.5, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=3.0, alpha_order=1, alpha_min=0.0, alpha_max=0.0)\n Parameters of the complex frequency-shifted absorption poles.\n\nNotes\n------\n\n **1D Model Illustration**\n\n Consider a transformed wave equation in the :math:`x` dimension below _`[1]`:\n\n .. math::\n\n \\left( \\left( \\frac{1}{s(x)} \\frac{\\delta}{\\delta x} \\right)^2 - \\frac{1}{c^2} \\frac{\\delta^2}{\\delta t^2} \\right) E = 0\n\n where the wave stretch factor :math:`s(x)` depends on the PML boundary position in the :math:`x` dimension.\n\n .. TODO what is x at 0?\n\n .. math::\n\n s(x) = \\left \\{\n \\begin{array}{lr}\n 1, & \\text{for } x < 0 \\\\\n 1 - \\frac{\\sigma}{i \\omega \\epsilon_0}, & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n The wave equation can be solved and plotted accordingly as a function of the :math:`x` dimension.\n\n .. math::\n\n E(x) = \\left \\{\n \\begin{array}{lr}\n e^{i(kx - \\omega t)}, & \\text{for } x < 0 \\\\\n e^{i(kx - \\omega t)} \\times e^{-\\frac{\\sigma x}{c \\epsilon_0}} & \\text{for } x > 0\n \\end{array}\n \\right \\}\n\n Hence, we see how this PML stretch factor induces frequency-independent exponential attentation and no\n reflection after the boundary at :math:`x=0`.\n\n .. image:: ../../_static/img/pml_boundary.png\n\n .. TODO make this image better\n\n **Usage Caveats**\n\n A perfectly matched layer (PML) is the most commonly used boundary condition in FDTD simulations to truncate\n a simulation domain and absorb outgoing radiation. However, many divergence issues are associated with the\n use of PML. One of the most common causes of a diverged simulation is structures inserted into PML at an angle.\n\n .. TODO links to absorber boundaries\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation.png\n\n Incorporating a dispersive material into the PML can also cause simulation divergence in certain scenarios.\n If your simulation lacks any structures inserted into the PML at an angle, but includes dispersive material\n in PML, it is advisable to substitute a nondispersive material for the dispersive material. Alternatively,\n if dispersion is necessary, switching from the :class:`PML` to :class:`Absorber` can effectively address the\n issue.\n\n The PML can effectively absorb outgoing radiation with minimum reflection as if the radiation just propagates\n into the free space. However, it\u2019s important to keep in mind that the PML only absorbs propagating fields. For\n evanescent fields, the PML can act as an amplification medium and cause a simulation to diverge. In Tidy3D,\n a warning will appear if the distance between a structure is smaller than half of a wavelength to prevent\n evanescent fields from leaking into PML. In most cases, the evanescent field will naturally die off within\n half a wavelength, but in some instances, a larger distance may be required.\n\n .. image:: ../../notebooks/img/diverged-fdtd-simulation1.png\n\n\n **References**\n\n .. [1] W.C. Chew and W.H. Weedon, Microwave and Optical Tech. Lett., 7 (13), 599,1994; S. Johnson, arXiv 2108.05348, 2021\n .. [2] Antonios Giannopoulos, IEEE Transactions on Antennas and Propagation, 56(9), 2995, 2008\n\nNote\n----\n\n For best results, structures that intersect with the PML or simulation edges should extend extend all the way\n through. In many such cases, an \u201cinfinite\u201d size ``td.inf`` can be used to define the size along that dimension.\n\nExample\n-------\n>>> pml = PML(num_layers=10)\n\nSee Also\n--------\n\n:class:`StablePML`:\n This PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Using FDTD to Compute a Transmission Spectrum `__\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "PML", + "enum": [ + "PML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of standard PML.", + "default": 12, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "PML Parameters", + "description": "Parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "StablePML": { + "title": "StablePML", + "description": "Specifies a 'stable' PML along a single dimension.\nThis PML deals handles possibly divergent simulations better, but at the expense of more layers.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of 'stable' PML.\nparameters : PMLParams = PMLParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=1.0, type='PMLParams', kappa_order=3, kappa_min=1.0, kappa_max=5.0, alpha_order=1, alpha_min=0.0, alpha_max=0.9)\n 'Stable' parameters of the complex frequency-shifted absorption poles.\n\nExample\n-------\n>>> pml = StablePML(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n:class:`Absorber`:\n Specifies an adiabatic absorber along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures:**\n * `Introduction to perfectly matched layer (PML) tutorial `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "StablePML", + "enum": [ + "StablePML" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of 'stable' PML.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Stable PML Parameters", + "description": "'Stable' parameters of the complex frequency-shifted absorption poles.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.0, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 5.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.9 + }, + "allOf": [ + { + "$ref": "#/definitions/PMLParams" + } + ] + } + }, + "additionalProperties": false + }, + "AbsorberParams": { + "title": "AbsorberParams", + "description": "Specifies parameters common to Absorbers and PMLs.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsigma_order : NonNegativeInt = 3\n Order of the polynomial describing the absorber profile (~dist^sigma_order).\nsigma_min : NonNegativeFloat = 0.0\n [units = 2*EPSILON_0/dt]. Minimum value of the absorber conductivity.\nsigma_max : NonNegativeFloat = 1.5\n [units = 2*EPSILON_0/dt]. Maximum value of the absorber conductivity.\n\nExample\n-------\n>>> params = AbsorberParams(sigma_order=3, sigma_min=0.0, sigma_max=1.5)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "sigma_order": { + "title": "Sigma Order", + "description": "Order of the polynomial describing the absorber profile (~dist^sigma_order).", + "default": 3, + "minimum": 0, + "type": "integer" + }, + "sigma_min": { + "title": "Sigma Minimum", + "description": "Minimum value of the absorber conductivity.", + "default": 0.0, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "sigma_max": { + "title": "Sigma Maximum", + "description": "Maximum value of the absorber conductivity.", + "default": 1.5, + "units": "2*EPSILON_0/dt", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "AbsorberParams", + "enum": [ + "AbsorberParams" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "Absorber": { + "title": "Absorber", + "description": "Specifies an adiabatic absorber along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nnum_layers : ConstrainedIntValue = 40\n Number of layers of absorber to add to + and - boundaries.\nparameters : AbsorberParams = AbsorberParams(attrs={}, sigma_order=3, sigma_min=0.0, sigma_max=6.4, type='AbsorberParams')\n Adiabatic absorber parameters.\n\nNotes\n-----\n\n This absorber is well-suited for dispersive materials intersecting with absorbing edges of the simulation at the\n expense of more layers.\n\n **Usage Caveats**\n\n Using absorber boundary is often a good remedy to resolve divergence issues related to :class:`PML`. The\n adiabatic absorber is a multilayer system with gradually increasing conductivity. The absorber usually has a\n larger undesired reflection compared to :class:`PML`. In practice, this small difference rarely matters,\n but is important to understand for simulations that require high accuracy.\n\n There are two possible sources for the reflection from absorbers. The first, and more common one, is that the\n ramping up of the conductivity is not sufficiently slow, which can be remedied by increasing the number of\n absorber layers (40 by default). The second one is that the absorption is not high enough, such that the\n light reaches the :class:`PEC` boundary at the end of the :class:`Absorber`, travels back through it,\n and is still not fully attenuated before re-entering the simulation region. If this is the case, increasing\n the maximum conductivity :class:`AbsorberParams` can help. In both cases, changing the order of the scaling\n of the conductivity (:attr:`tidy3d.AbsorberParams.sigma_order`) can also have an effect, but this is a more\n advanced setting that we typically do not recommend modifying.\n\nExample\n-------\n>>> pml = Absorber(num_layers=40)\n\nSee Also\n--------\n\n:class:`PML`:\n A standard PML along a single dimension.\n\n**Notebooks:**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "Absorber", + "enum": [ + "Absorber" + ], + "type": "string" + }, + "num_layers": { + "title": "Number of Layers", + "description": "Number of layers of absorber to add to + and - boundaries.", + "default": 40, + "minimum": 1, + "type": "integer" + }, + "parameters": { + "title": "Absorber Parameters", + "description": "Adiabatic absorber parameters.", + "default": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 6.4, + "type": "AbsorberParams" + }, + "allOf": [ + { + "$ref": "#/definitions/AbsorberParams" + } + ] + } + }, + "additionalProperties": false + }, + "BlochBoundary": { + "title": "BlochBoundary", + "description": "Specifies a Bloch boundary condition along a single dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional unique name for boundary.\nbloch_vec : float\n Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.\n\nExample\n-------\n>>> bloch = BlochBoundary(bloch_vec=1)\n\nSee Also\n--------\n\n**Notebooks**:\n * `Defining a total-field scattered-field (TFSF) plane wave source <../../notebooks/TFSF.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional unique name for boundary.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "BlochBoundary", + "enum": [ + "BlochBoundary" + ], + "type": "string" + }, + "bloch_vec": { + "title": "Normalized Bloch vector component", + "description": "Normalized component of the Bloch vector in units of 2 * pi / (size along dimension) in the background medium, along the dimension in which the boundary is specified.", + "type": "number" + } + }, + "required": [ + "bloch_vec" + ], + "additionalProperties": false + }, + "Boundary": { + "title": "Boundary", + "description": "Boundary conditions at the minus and plus extents along a dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the plus side along a dimension.\nminus : Union[Periodic, PECBoundary, PMCBoundary, PML, StablePML, Absorber, BlochBoundary] = PML(attrs={}, name=None, type='PML', num_layers=12, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0))\n Boundary condition on the minus side along a dimension.\n\nNotes\n-----\n\n To specify individual boundary conditions along different dimensions, instead of :class:`BoundarySpec`,\n this class is used, which defines the ``plus`` and ``minus`` boundaries along a single\n dimension.\n\nExample\n-------\n>>> boundary = Boundary(plus = PML(), minus = PECBoundary())\n\nSee Also\n--------\n\n:class:`BoundarySpec`\n Specifies boundary conditions on each side of the domain and along each dimension.\n\n:class:`PML`\n A standard PML along a single dimension.\n\n**Notebooks**\n * `Setting up boundary conditions <../../notebooks/BoundaryConditions.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "plus": { + "title": "Plus BC", + "description": "Boundary condition on the plus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "minus": { + "title": "Minus BC", + "description": "Boundary condition on the minus side along a dimension.", + "default": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Periodic": "#/definitions/Periodic", + "PECBoundary": "#/definitions/PECBoundary", + "PMCBoundary": "#/definitions/PMCBoundary", + "PML": "#/definitions/PML", + "StablePML": "#/definitions/StablePML", + "Absorber": "#/definitions/Absorber", + "BlochBoundary": "#/definitions/BlochBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Periodic" + }, + { + "$ref": "#/definitions/PECBoundary" + }, + { + "$ref": "#/definitions/PMCBoundary" + }, + { + "$ref": "#/definitions/PML" + }, + { + "$ref": "#/definitions/StablePML" + }, + { + "$ref": "#/definitions/Absorber" + }, + { + "$ref": "#/definitions/BlochBoundary" + } + ] + }, + "type": { + "title": "Type", + "default": "Boundary", + "enum": [ + "Boundary" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "BoundarySpec": { + "title": "BoundarySpec", + "description": "Specifies boundary conditions on each side of the domain and along each dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nx : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\ny : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\nz : Boundary = Boundary(attrs={}, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)), type='Boundary')\n Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.\n\nNotes\n-----\n\n This :class:`BoundarySpec` object defines the boundary conditions applied on each of the 6 domain edges,\n and is provided as an input to the simulation.\n\n A :class:`BoundarySpec` consists of three :class:`Boundary` objects, each defining the boundaries on the plus\n and minus side of each dimension. In most cases, one just wants to specify whether there are absorbing\n :class:`PML` layers along any of the ``x``, ``y``, ``z`` dimensions. By default, ``tidy3d`` simulations have\n :class:`PML` boundaries on all sides.\n\n If we want to explicitly set the boundaries, we can use the :attr:`tidy3d.BoundarySpec.all_sides` method.\n This can be used to set any type of boundary condition on all sides of the simulation. We can also set\n :class:`PML` on specified sides only by calling the :attr:`tidy3d.BoundarySpec.pml` method, e.g. ``BoundarySpec.pml(\n x=False, y=False, z=False)``. This will put :class:`PML` along the dimensions defined as ``True``,\n and set periodic boundaries along the other dimensions.\n\n\nSee Also\n--------\n\n:class:`Boundary`\n Boundary conditions at the minus and plus extents along a dimension.\n\n**Notebooks**\n * `How to troubleshoot a diverged FDTD simulation <../../notebooks/DivergedFDTDSimulation.html>`_\n\n**Lectures**\n * `Using FDTD to Compute a Transmission Spectrum `__", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "x": { + "title": "Boundary condition along x.", + "description": "Boundary condition on the plus and minus sides along the x axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "y": { + "title": "Boundary condition along y.", + "description": "Boundary condition on the plus and minus sides along the y axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "z": { + "title": "Boundary condition along z.", + "description": "Boundary condition on the plus and minus sides along the z axis. If ``None``, periodic boundaries are applied. Default will change to PML in 2.0 so explicitly setting the boundaries is recommended.", + "default": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "allOf": [ + { + "$ref": "#/definitions/Boundary" + } + ] + }, + "type": { + "title": "Type", + "default": "BoundarySpec", + "enum": [ + "BoundarySpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ApodizationSpec": { + "title": "ApodizationSpec", + "description": "Stores specifications for the apodizaton of frequency-domain monitors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstart : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the start apodization ends.\nend : Optional[NonNegativeFloat] = None\n [units = sec]. Defines the time at which the end apodization begins.\nwidth : Optional[PositiveFloat] = None\n [units = sec]. Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.\n\nExample\n-------\n>>> apod_spec = ApodizationSpec(start=1, end=2, width=0.2)\n\n\n.. image:: ../../_static/img/apodization.png\n :width: 80%\n :align: center", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "start": { + "title": "Start Interval", + "description": "Defines the time at which the start apodization ends.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "end": { + "title": "End Interval", + "description": "Defines the time at which the end apodization begins.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "width": { + "title": "Apodization Width", + "description": "Characteristic decay length of the apodization function, i.e., the width of the ramping up of the scaling function from 0 to 1.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "ApodizationSpec", + "enum": [ + "ApodizationSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "FieldMonitor": { + "title": "FieldMonitor", + "description": ":class:`Monitor` that records electromagnetic fields in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\n\nNotes\n-----\n\n :class:`FieldMonitor` objects operate by running a discrete Fourier transform of the fields at a given set of\n frequencies to perform the calculation \u201cin-place\u201d with the time stepping. :class:`FieldMonitor` objects are\n useful for investigating the steady-state field distribution in 2D and 3D regions of the simulation.\n\nExample\n-------\n>>> monitor = FieldMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... fields=['Hx'],\n... freqs=[250e12, 300e12],\n... name='steady_state_monitor',\n... colocate=True)\n\n\nSee Also\n--------\n\n**Notebooks**\n\n* `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n\n**Lectures**\n\n* `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldMonitor", + "enum": [ + "FieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "FieldTimeMonitor": { + "title": "FieldTimeMonitor", + "description": ":class:`Monitor` that records electromagnetic fields in the time domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nstart : NonNegativeFloat = 0.0\n [units = sec]. Time at which to start monitor recording.\nstop : Optional[NonNegativeFloat] = None\n [units = sec]. Time at which to stop monitor recording. If not specified, record until end of simulation.\ninterval : Optional[PositiveInt] = None\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\n\nNotes\n-----\n\n :class:`FieldTimeMonitor` objects are best used to monitor the time dependence of the fields at a single\n point, but they can also be used to create \u201canimations\u201d of the field pattern evolution.\n\n To create an animation, we need to capture the frames at different time instances of the simulation. This can\n be done by using a :class:`FieldTimeMonitor`. Usually a FDTD simulation contains a large number of time steps\n and grid points. Recording the field at every time step and grid point will result in a large dataset. For\n the purpose of making animations, this is usually unnecessary.\n\n\nExample\n-------\n>>> monitor = FieldTimeMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... fields=['Hx'],\n... start=1e-13,\n... stop=5e-13,\n... interval=2,\n... colocate=True,\n... name='movie_monitor')\n\n\nSee Also\n--------\n\n**Notebooks**\n * `First walkthrough <../../notebooks/Simulation.html>`_: Usage in a basic simulation flow.\n * `Creating FDTD animations <../../notebooks/AnimationTutorial.html>`_.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldTimeMonitor", + "enum": [ + "FieldTimeMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "start": { + "title": "Start Time", + "description": "Time at which to start monitor recording.", + "default": 0.0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "stop": { + "title": "Stop Time", + "description": "Time at which to stop monitor recording. If not specified, record until end of simulation.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "interval": { + "title": "Time Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "AuxFieldTimeMonitor": { + "title": "AuxFieldTimeMonitor", + "description": ":class:`.Monitor` that records auxiliary fields in the time domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nstart : NonNegativeFloat = 0.0\n [units = sec]. Time at which to start monitor recording.\nstop : Optional[NonNegativeFloat] = None\n [units = sec]. Time at which to stop monitor recording. If not specified, record until end of simulation.\ninterval : Optional[PositiveInt] = None\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.\nfields : Tuple[Literal['Nfx', 'Nfy', 'Nfz'], ...] = ()\n Collection of auxiliary field components to store in the monitor. Auxiliary fields which are not present in the simulation will be zero.\n\nAuxiliary fields are used in certain nonlinear material models.\n:class:`.TwoPhotonAbsorption` uses `Nfx`, `Nfy`, and `Nfz` for the\nfree-carrier density.\n\nExample\n-------\n>>> monitor = AuxFieldTimeMonitor(\n... center=(1,2,3),\n... size=(0,0,0),\n... fields=['Nfx'],\n... start=1e-13,\n... stop=5e-13,\n... interval=2,\n... colocate=True,\n... name='aux_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "AuxFieldTimeMonitor", + "enum": [ + "AuxFieldTimeMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "start": { + "title": "Start Time", + "description": "Time at which to start monitor recording.", + "default": 0.0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "stop": { + "title": "Stop Time", + "description": "Time at which to stop monitor recording. If not specified, record until end of simulation.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "interval": { + "title": "Time Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "fields": { + "title": "Aux Field Components", + "description": "Collection of auxiliary field components to store in the monitor. Auxiliary fields which are not present in the simulation will be zero.", + "default": [], + "type": "array", + "items": { + "enum": [ + "Nfx", + "Nfy", + "Nfz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "PermittivityMonitor": { + "title": "PermittivityMonitor", + "description": ":class:`Monitor` that records the diagonal components of the complex-valued relative\npermittivity tensor in the frequency domain. The recorded data has the same shape as a\n:class:`.FieldMonitor` of the same geometry: the permittivity values are saved at the\nYee grid locations, and can be interpolated to any point inside the monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : Literal[False] = False\n Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n This field is ignored in this monitor.\n\nNotes\n-----\n\n If 2D materials are present, then the permittivity values correspond to the\n volumetric equivalent of the 2D materials.\n\n .. TODO add links to relevant areas\n\nExample\n-------\n>>> monitor = PermittivityMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='eps_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PermittivityMonitor", + "enum": [ + "PermittivityMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Colocation turned off, since colocated permittivity values do not have a physical meaning - they do not correspond to the subpixel-averaged ones.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "This field is ignored in this monitor.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "FluxMonitor": { + "title": "FluxMonitor", + "description": ":class:`Monitor` that records power flux in the frequency domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\n\nNotes\n-----\n\n If the monitor geometry is a 2D box, the total flux through this plane is returned, with a\n positive sign corresponding to power flow in the positive direction along the axis normal to\n the plane. If the geometry is a 3D box, the total power coming out of the box is returned by\n integrating the flux over all box surfaces (except the ones defined in ``exclude_surfaces``).\n\nExample\n-------\n>>> monitor = FluxMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... name='flux_monitor')\n\nSee Also\n--------\n\n**Notebooks**\n\n* `THz integrated demultiplexer/filter based on a ring resonator <../../notebooks/THzDemultiplexerFilter.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FluxMonitor", + "enum": [ + "FluxMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "FluxTimeMonitor": { + "title": "FluxTimeMonitor", + "description": ":class:`Monitor` that records power flux in the time domain.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nstart : NonNegativeFloat = 0.0\n [units = sec]. Time at which to start monitor recording.\nstop : Optional[NonNegativeFloat] = None\n [units = sec]. Time at which to stop monitor recording. If not specified, record until end of simulation.\ninterval : Optional[PositiveInt] = None\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\n\nNotes\n-----\n\n If the monitor geometry is a 2D box, the total flux through this plane is returned, with a\n positive sign corresponding to power flow in the positive direction along the axis normal to\n the plane. If the geometry is a 3D box, the total power coming out of the box is returned by\n integrating the flux over all box surfaces (except the ones defined in ``exclude_surfaces``).\n\nExample\n-------\n>>> monitor = FluxTimeMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... start=1e-13,\n... stop=5e-13,\n... interval=2,\n... name='flux_vs_time')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FluxTimeMonitor", + "enum": [ + "FluxTimeMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "start": { + "title": "Start Time", + "description": "Time at which to start monitor recording.", + "default": 0.0, + "units": "sec", + "minimum": 0, + "type": "number" + }, + "stop": { + "title": "Stop Time", + "description": "Time at which to stop monitor recording. If not specified, record until end of simulation.", + "units": "sec", + "minimum": 0, + "type": "number" + }, + "interval": { + "title": "Time Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values downsample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "ModeMonitor": { + "title": "ModeMonitor", + "description": ":class:`Monitor` that records amplitudes from modal decomposition of fields on plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\n\nNotes\n------\n\n The fields recorded by frequency monitors (and hence also mode monitors) are automatically\n normalized by the power amplitude spectrum of the source. For multiple sources, the user can\n select which source to use for the normalization too.\n\n We can also use the mode amplitudes recorded in the mode monitor to reveal the decomposition\n of the radiated power into forward- and backward-propagating modes, respectively.\n\n .. TODO give an example of how to extract the data from this mode.\n\n .. TODO add derivation in the notebook.\n\n .. TODO add link to method\n\n .. TODO add links to notebooks correspondingly\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')\n\nSee Also\n--------\n\n**Notebooks**:\n * `ModalSourcesMonitors <../../notebooks/ModalSourcesMonitors.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeMonitor", + "enum": [ + "ModeMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "store_fields_direction": { + "title": "Store Fields", + "description": "Propagation direction for the mode field profiles stored from mode solving.", + "enum": [ + "+", + "-" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "ModeSolverMonitor": { + "title": "ModeSolverMonitor", + "description": ":class:`Monitor` that stores the mode field profiles returned by the mode solver in the\nmonitor plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nstore_fields_direction : Optional[Literal['+', '-']] = None\n Propagation direction for the mode field profiles stored from mode solving.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nExample\n-------\n>>> mode_spec = ModeSpec(num_modes=3)\n>>> monitor = ModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[200e12, 210e12],\n... mode_spec=mode_spec,\n... name='mode_monitor')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeSolverMonitor", + "enum": [ + "ModeSolverMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes).", + "default": true, + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "store_fields_direction": { + "title": "Store Fields", + "description": "Propagation direction for the mode field profiles stored from mode solving.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "direction": { + "title": "Propagation Direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "FieldProjectionAngleMonitor": { + "title": "FieldProjectionAngleMonitor", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them at given observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNotes\n-----\n\n .. TODO this needs an illustration\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` parameters define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`phi`, :attr:`theta`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n **Usage Caveats**\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the\n fields are propagating in a homogeneous medium. Therefore, one should use :class:`PML` / :class:`Absorber` as\n boundary conditions in the part of the domain where fields are projected.\n\n .. TODO why not add equation here\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases. For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. TODO TYPO FIX o that the approximations are not used, and the projection is accurate even just a few wavelengths away from the near field locations.\n\n By default, if no :attr:`proj_distance` was provided, the fields are projected to a distance of 1m.\n\n **Server-side field projection Application**\n\n Provide the :class:`FieldProjectionAngleMonitor` monitor as an input to the\n :class:`Simulation` object as one of its monitors. Now, we no longer need to provide a separate near-field\n :class:`FieldMonitor` - the near fields will automatically be recorded based on the size and location of the\n ``FieldProjectionAngleMonitor``. Note also that in some cases, the server-side computations may be slightly\n more accurate than client-side ones, because on the server, the near fields are not downsampled at all.\n\n We can re-project the already-computed far fields to a different distance away from the structure - we\n neither need to run another simulation nor re-run the :class:`FieldProjector`.\n\n **Far-Field Approximation Selection**\n\n .. TODO unsure if add on params?\n\n If the distance between the near and far field locations is\n much larger than the size of the device, one can typically set :attr:`far_field_approx` to\n ``True``, which will make use of the far-field approximation to speed up calculations.\n If the projection distance is comparable to the size of the device, we recommend setting\n :attr:`far_field_approx` to ``False``.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO Fix that image so remove right irrelevant side\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter :attr:`far_field_approx` to ``False`` in the\n ``FieldProjectionAngleMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include here inherited methods.\n\nExample\n-------\n>>> monitor = FieldProjectionAngleMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... phi=[0, np.pi/2],\n... theta=np.linspace(-np.pi/2, np.pi/2, 100),\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_: Realistic case study further demonstrating the accuracy of the field projections.\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_: For far field projections in the context of perdiodic boundary conditions.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldProjectionAngleMonitor", + "enum": [ + "FieldProjectionAngleMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + }, + "custom_origin": { + "title": "Local Origin", + "description": "Local origin used for defining observation points. If ``None``, uses the monitor's center.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "far_field_approx": { + "title": "Far Field Approximation", + "description": "Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.", + "default": true, + "type": "boolean" + }, + "window_size": { + "title": "Spatial filtering window size", + "description": "Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "medium": { + "title": "Projection medium", + "description": "Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "proj_distance": { + "title": "Projection Distance", + "description": "Radial distance of the projection points from ``local_origin``.", + "default": 1000000.0, + "units": "um", + "type": "number" + }, + "theta": { + "title": "Polar Angles", + "description": "Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.", + "units": "rad", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "phi": { + "title": "Azimuth Angles", + "description": "Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.", + "units": "rad", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs", + "theta", + "phi" + ], + "additionalProperties": false + }, + "FieldProjectionCartesianMonitor": { + "title": "FieldProjectionCartesianMonitor", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on a Cartesian observation plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Signed distance of the projection plane along ``proj_axis``. from the plane containing ``local_origin``.\nx : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local x observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global y axis. When ``proj_axis`` is 1, this corresponds to the global x axis. When ``proj_axis`` is 2, this corresponds to the global x axis. \ny : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = um]. Local y observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global z axis. When ``proj_axis`` is 1, this corresponds to the global z axis. When ``proj_axis`` is 2, this corresponds to the global y axis. \n\nNotes\n-----\n\n **Parameters Caveats**\n\n The :attr:`center` and :attr:`size` fields define\n where the monitor will be placed in order to record near fields, typically very close\n to the structure of interest. The near fields are then projected\n to far-field locations defined by :attr:`x`, :attr:`y`, and :attr:`proj_distance`, relative\n to the :attr:`custom_origin`.\n\n Here, :attr:`x` and :attr:`y`, correspond to a local coordinate system\n where the local ``z`` axis is defined by :attr:`proj_axis`: which is the axis normal to this monitor.\n\n **Far-Field Approximation Selection**\n\n If the distance between the near and far field locations is much larger than the size of the\n device, one can typically set :attr:`far_field_approx` to ``True``, which will make use of the\n far-field approximation to speed up calculations. If the projection distance is comparable\n to the size of the device, we recommend setting :attr:`far_field_approx` to ``False``,\n so that the approximations are not used, and the projection is accurate even just a few\n wavelengths away from the near field locations.\n\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n .. image:: ../../notebooks/img/n2f_diagram.png\n\n .. TODO unsure if add on params?\n\n When selected, it is assumed that:\n\n - The fields are measured at a distance much greater than the size of our simulation in the transverse\n direction.\n - The geometric approximations imply that any quantity whose magnitude drops off as\n :math:`\\frac{1}{r^2}` or faster is ignored.\n\n The advantages of these approximations are:\n\n * The projections are computed relatively fast.\n * The projections are cast in a simple mathematical form.\n which allows re-projecting the fields to different distance without the need to re-run a simulation or to\n re-run the :class:`FieldProjector`.\n\n\n In cases where we may want to project to intermediate distances where the far field approximation is no\n longer valid, simply include the class definition parameter ``far_field_approx=False`` in the\n ``FieldProjectionCartesianMonitor`` instantiation. The resulting computations will be a bit slower,\n but the results will be significantly more accurate.\n\n .. TODO include this example\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a DiffractionMonitor.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionCartesianMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... x=[-1, 0, 1],\n... y=[-2, -1, 0, 1, 2],\n... proj_axis=2,\n... proj_distance=5,\n... far_field_approx=True,\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldProjectionCartesianMonitor", + "enum": [ + "FieldProjectionCartesianMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + }, + "custom_origin": { + "title": "Local Origin", + "description": "Local origin used for defining observation points. If ``None``, uses the monitor's center.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "far_field_approx": { + "title": "Far Field Approximation", + "description": "Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.", + "default": true, + "type": "boolean" + }, + "window_size": { + "title": "Spatial filtering window size", + "description": "Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "medium": { + "title": "Projection medium", + "description": "Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "proj_axis": { + "title": "Projection Plane Axis", + "description": "Axis along which the observation plane is oriented.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "proj_distance": { + "title": "Projection Distance", + "description": "Signed distance of the projection plane along ``proj_axis``. from the plane containing ``local_origin``.", + "default": 1000000.0, + "units": "um", + "type": "number" + }, + "x": { + "title": "Local x Observation Coordinates", + "description": "Local x observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global y axis. When ``proj_axis`` is 1, this corresponds to the global x axis. When ``proj_axis`` is 2, this corresponds to the global x axis. ", + "units": "um", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "y": { + "title": "Local y Observation Coordinates", + "description": "Local y observation coordinates w.r.t. ``local_origin`` and ``proj_axis``. When ``proj_axis`` is 0, this corresponds to the global z axis. When ``proj_axis`` is 1, this corresponds to the global z axis. When ``proj_axis`` is 2, this corresponds to the global y axis. ", + "units": "um", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs", + "proj_axis", + "x", + "y" + ], + "additionalProperties": false + }, + "FieldProjectionKSpaceMonitor": { + "title": "FieldProjectionKSpaceMonitor", + "description": ":class:`Monitor` that samples electromagnetic near fields in the frequency domain\nand projects them on an observation plane defined in k-space.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_axis : Literal[0, 1, 2]\n Axis along which the observation plane is oriented.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\nux : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local x component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\nuy : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Local y component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].\n\n Notes\n -----\n\n The :attr:`center` and :attr:`size`\n fields define where the monitor will be placed in order to record near fields, typically\n very close to the structure of interest. The near fields are then\n projected to far-field locations defined in k-space by ``ux``, ``uy``, and ``proj_distance``,\n relative to the ``custom_origin``. Here, ``ux`` and ``uy`` are associated with a local\n coordinate system where the local 'z' axis is defined by ``proj_axis``: which is the axis\n normal to this monitor. If the distance between the near and far field locations is much\n larger than the size of the device, one can typically set ``far_field_approx`` to ``True``,\n which will make use of the far-field approximation to speed up calculations. If the\n projection distance is comparable to the size of the device, we recommend setting\n ``far_field_approx`` to ``False``, so that the approximations are not used, and the\n projection is accurate even just a few wavelengths away from the near field locations.\n For applications where the monitor is an open surface rather than a box that\n encloses the device, it is advisable to pick the size of the monitor such that the\n recorded near fields decay to negligible values near the edges of the monitor.\n\n **Usage Caveats**\n\n .. TODO I believe a little illustration here would be handy.\n\n Since field projections rely on the surface equivalence principle, we have assumed that the tangential near\n fields recorded on the near field monitor serve as equivalent sources which generate the correct far fields.\n However, this requires that the field strength decays nearly to zero near the edges of the near-field\n monitor, which may not always be the case. For example, if we had used a larger aperture compared to the full\n simulation size in the transverse direction, we may expect a degradation in accuracy of the field\n projections. Despite this limitation, the field projections are still remarkably accurate in realistic\n scenarios. For realistic case studies further demonstrating the accuracy of the field projections,\n see our metalens and zone plate case studies.\n\n The field projections make use of the analytical homogeneous medium Green\u2019s function, which assumes that the fields\n are propagating in a homogeneous medium. Therefore, one should use PMLs / absorbers as boundary conditions in the\n part of the domain where fields are projected. For far field projections in the context of perdiodic boundary\n conditions, see the diffraction efficiency example which demonstrates the use of a :class:`DiffractionMonitor`.\n\n Server-side field projections will add to the monetary cost of the simulation. However, typically the far field\n projections have a very small computation cost compared to the FDTD simulation itself, so the increase in monetary\n cost should be negligibly small in most cases.\n\nExample\n-------\n>>> monitor = FieldProjectionKSpaceMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[250e12, 300e12],\n... name='n2f_monitor',\n... custom_origin=(1,2,3),\n... proj_axis=2,\n... ux=[0.1,0.2],\n... uy=[0.3,0.4,0.5]\n... )\n\nSee Also\n--------\n\n**Notebooks**:\n * `Performing near field to far field projections <../../notebooks/FieldProjections.html>`_\n * `Field projection for a zone plate <../../notebooks/ZonePlateFieldProjection.html>`_\n * `Metalens in the visible frequency range <../../notebooks/Metalens.html>`_\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "FieldProjectionKSpaceMonitor", + "enum": [ + "FieldProjectionKSpaceMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + }, + "custom_origin": { + "title": "Local Origin", + "description": "Local origin used for defining observation points. If ``None``, uses the monitor's center.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "far_field_approx": { + "title": "Far Field Approximation", + "description": "Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.", + "default": true, + "type": "boolean" + }, + "window_size": { + "title": "Spatial filtering window size", + "description": "Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "medium": { + "title": "Projection medium", + "description": "Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "proj_axis": { + "title": "Projection Plane Axis", + "description": "Axis along which the observation plane is oriented.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "proj_distance": { + "title": "Projection Distance", + "description": "Radial distance of the projection points from ``local_origin``.", + "default": 1000000.0, + "units": "um", + "type": "number" + }, + "ux": { + "title": "Normalized kx", + "description": "Local x component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "uy": { + "title": "Normalized ky", + "description": "Local y component of wave vectors on the observation plane, relative to ``local_origin`` and oriented with respect to ``proj_axis``, normalized by (2*pi/lambda) where lambda is the wavelength associated with the background medium. Must be in the range [-1, 1].", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs", + "proj_axis", + "ux", + "uy" + ], + "additionalProperties": false + }, + "DiffractionMonitor": { + "title": "DiffractionMonitor", + "description": ":class:`Monitor` that uses a 2D Fourier transform to compute the\ndiffraction amplitudes and efficiency for allowed diffraction orders.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.\ncolocate : Literal[False] = False\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Literal['+', '-'] = +\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Defaults to ``'+'`` if not provided.\n\nExample\n-------\n>>> monitor = DiffractionMonitor(\n... center=(1,2,3),\n... size=(inf,inf,0),\n... freqs=[250e12, 300e12],\n... name='diffraction_monitor',\n... normal_dir='+',\n... )\n\nSee Also\n--------\n\n**Notebooks**\n * `Multilevel blazed diffraction grating <../../notebooks/GratingEfficiency.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "DiffractionMonitor", + "enum": [ + "DiffractionMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": false, + "enum": [ + false + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Defaults to ``'+'`` if not provided.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "freqs" + ], + "additionalProperties": false + }, + "DirectivityMonitor": { + "title": "DirectivityMonitor", + "description": ":class:`Monitor` that records the radiation characteristics of antennas in the frequency domain\nat specified observation angles.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = Hz]. Array or list of frequencies stored by the field monitor.\napodization : ApodizationSpec = ApodizationSpec(attrs={}, start=None, end=None, width=None, type='ApodizationSpec')\n Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.\nnormal_dir : Optional[Literal['+', '-']] = None\n Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.\nexclude_surfaces : Optional[Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...]] = None\n Surfaces to exclude in the integration, if a volume monitor.\ncustom_origin : Optional[Tuple[float, float, float]] = None\n [units = um]. Local origin used for defining observation points. If ``None``, uses the monitor's center.\nfar_field_approx : bool = True\n Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.\nwindow_size : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D] = None\n Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.\nproj_distance : float = 1000000.0\n [units = um]. Radial distance of the projection points from ``local_origin``.\ntheta : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\nphi : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n [units = rad]. Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.\n\nNote\n----\nFor directivity, the computation is based on the ratio of the radiation\nintensity in a given direction to the average radiation intensity\nover all directions:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.6 (2016).\n\nFor axial ratio, the computation is based on:\n\n Balanis, Constantine A., \"Antenna Theory: Analysis and Design,\"\n John Wiley & Sons, Chapter 2.12 (2016).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "DirectivityMonitor", + "enum": [ + "DirectivityMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals at which near fields are recorded for projection to the far field, along each direction. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Using values greater than 1 can help speed up server-side far field projections with minimal accuracy loss, especially in cases where it is necessary for the grid resolution to be high for the FDTD simulation, but such a high resolution is unnecessary for the purpose of projecting the recorded near fields to the far field.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid). Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "freqs": { + "title": "Frequencies", + "description": "Array or list of frequencies stored by the field monitor.", + "units": "Hz", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "apodization": { + "title": "Apodization Specification", + "description": "Sets parameters of (optional) apodization. Apodization applies a windowing function to the Fourier transform of the time-domain fields into frequency-domain ones, and can be used to truncate the beginning and/or end of the time signal, for example to eliminate the source pulse when studying the eigenmodes of a system. Note: apodization affects the normalization of the frequency-domain fields.", + "default": { + "attrs": {}, + "start": null, + "end": null, + "width": null, + "type": "ApodizationSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ApodizationSpec" + } + ] + }, + "normal_dir": { + "title": "Normal Vector Orientation", + "description": "Direction of the surface monitor's normal vector w.r.t. the positive x, y or z unit vectors. Must be one of ``'+'`` or ``'-'``. Applies to surface monitors only, and defaults to ``'+'`` if not provided.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "exclude_surfaces": { + "title": "Excluded Surfaces", + "description": "Surfaces to exclude in the integration, if a volume monitor.", + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + }, + "custom_origin": { + "title": "Local Origin", + "description": "Local origin used for defining observation points. If ``None``, uses the monitor's center.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "far_field_approx": { + "title": "Far Field Approximation", + "description": "Whether to enable the far field approximation when projecting fields. If ``True``, terms that decay as O(1/r^2) are ignored, as are the radial components of fields. Typically, this should be set to ``True`` only when the projection distance is much larger than the size of the device being modeled, and the projected points are in the far field of the device.", + "default": true, + "type": "boolean" + }, + "window_size": { + "title": "Spatial filtering window size", + "description": "Size of the transition region of the windowing function used to ensure that the recorded near fields decay to zero near the edges of the monitor. The two components refer to the two tangential directions associated with each surface. For surfaces with the normal along ``x``, the two components are (``y``, ``z``). For surfaces with the normal along ``y``, the two components are (``x``, ``z``). For surfaces with the normal along ``z``, the two components are (``x``, ``y``). Each value must be between 0 and 1, inclusive, and denotes the size of the transition region over which fields are scaled to less than a thousandth of the original amplitude, relative to half the size of the monitor in that direction. A value of 0 turns windowing off in that direction, while a value of 1 indicates that the window will be applied to the entire monitor in that direction. This field is applicable for surface monitors only, and otherwise must remain (0, 0).", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "medium": { + "title": "Projection medium", + "description": "Medium through which to project fields. Generally, the fields should be projected through the same medium as the one in which this monitor is placed, and this is the default behavior when ``medium=None``. A custom ``medium`` can be useful in some situations for advanced users, but we recommend trying to avoid using a non-default ``medium``.", + "anyOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + } + ] + }, + "proj_distance": { + "title": "Projection Distance", + "description": "Radial distance of the projection points from ``local_origin``.", + "default": 1000000.0, + "units": "um", + "type": "number" + }, + "theta": { + "title": "Polar Angles", + "description": "Polar angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.", + "units": "rad", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "phi": { + "title": "Azimuth Angles", + "description": "Azimuth angles with respect to the global z axis, relative to the location of ``local_origin``, at which to project fields.", + "units": "rad", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + } + }, + "required": [ + "size", + "name", + "freqs", + "theta", + "phi" + ], + "additionalProperties": false + }, + "UniformGrid": { + "title": "UniformGrid", + "description": "Uniform 1D grid. The most standard way to define a simulation is to use a constant grid size in each of the three directions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\n\nExample\n-------\n>>> grid_1d = UniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`QuasiUniformGrid`\n Specification for quasi-uniform grid along a given dimension.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Photonic crystal waveguide polarization filter <../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "UniformGrid", + "enum": [ + "UniformGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "CustomGrid": { + "title": "CustomGrid", + "description": "Custom 1D grid supplied as a list of grid cell sizes centered on the simulation center.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndl : Tuple[PositiveFloat, ...]\n [units = um]. An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.\ncustom_offset : Optional[float] = None\n [units = um]. The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.\n\nExample\n-------\n>>> grid_1d = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGrid", + "enum": [ + "CustomGrid" + ], + "type": "string" + }, + "dl": { + "title": "Customized grid sizes.", + "description": "An array of custom nonuniform grid sizes. The resulting grid is centered on the simulation center such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``, unless a ``custom_offset`` is given. Note: if supplied sizes do not cover the simulation size, the first and last sizes are repeated to cover the simulation domain.", + "units": "um", + "type": "array", + "items": { + "type": "number", + "exclusiveMinimum": 0 + } + }, + "custom_offset": { + "title": "Customized grid offset.", + "description": "The starting coordinate of the grid which defines the simulation center. If ``None``, the simulation center is set such that it spans the region ``(center - sum(dl)/2, center + sum(dl)/2)``.", + "units": "um", + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GradedMesher": { + "title": "GradedMesher", + "description": "Implements automatic nonuniform meshing with a set minimum steps per wavelength and\na graded mesh expanding from higher- to lower-resolution regions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GradedMesher", + "enum": [ + "GradedMesher" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AutoGrid": { + "title": "AutoGrid", + "description": "Specification for non-uniform grid along a given dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\nmin_steps_per_wvl : ConstrainedFloatValue = 10.0\n Minimal number of steps per wavelength in each medium.\nmin_steps_per_sim_size : ConstrainedFloatValue = 10.0\n Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.\n\nExample\n-------\n>>> grid_1d = AutoGrid(min_steps_per_wvl=16, max_scale=1.4)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`GridSpec`\n Collective grid specification for all three dimensions.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "AutoGrid", + "enum": [ + "AutoGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "min_steps_per_wvl": { + "title": "Minimal Number of Steps Per Wavelength", + "description": "Minimal number of steps per wavelength in each medium.", + "default": 10.0, + "minimum": 6.0, + "type": "number" + }, + "min_steps_per_sim_size": { + "title": "Minimal Number of Steps Per Simulation Domain Size", + "description": "Minimal number of steps per longest edge length of simulation domain bounding box. This is useful when the simulation domain size is subwavelength.", + "default": 10.0, + "minimum": 1.0, + "type": "number" + } + }, + "additionalProperties": false + }, + "CustomGridBoundaries": { + "title": "CustomGridBoundaries", + "description": "Custom 1D grid supplied as a list of grid cell boundary coordinates.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncoords : ArrayLike[dtype=float, ndim=1]\n [units = um]. An array of grid boundary coordinates.\n\nExample\n-------\n>>> grid_1d = CustomGridBoundaries(coords=[-0.2, 0.0, 0.2, 0.4, 0.5, 0.6, 0.7])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomGridBoundaries", + "enum": [ + "CustomGridBoundaries" + ], + "type": "string" + }, + "coords": { + "title": "Grid Boundary Coordinates", + "description": "An array of grid boundary coordinates.", + "units": "um", + "type": "ArrayLike" + } + }, + "required": [ + "coords" + ], + "additionalProperties": false + }, + "QuasiUniformGrid": { + "title": "QuasiUniformGrid", + "description": "Similar to :class:`UniformGrid` that generates uniform 1D grid, but grid positions\nare locally fine tuned to be snaped to snapping points and the edges of structure bounding boxes.\nInternally, it is using the same meshing method as :class:`AutoGrid`, but it ignores material information in\nfavor for a user-defined grid size.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmax_scale : ConstrainedFloatValue = 1.4\n Sets the maximum ratio between any two consecutive grid steps.\nmesher : GradedMesher = GradedMesher(attrs={}, type='GradedMesher')\n The type of mesher to use to generate the grid automatically.\ndl_min : Optional[NonNegativeFloat] = None\n [units = um]. Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.\ndl : PositiveFloat\n [units = um]. Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.\n\nExample\n-------\n>>> grid_1d = QuasiUniformGrid(dl=0.1)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "QuasiUniformGrid", + "enum": [ + "QuasiUniformGrid" + ], + "type": "string" + }, + "max_scale": { + "title": "Maximum Grid Size Scaling", + "description": "Sets the maximum ratio between any two consecutive grid steps.", + "default": 1.4, + "exclusiveMaximum": 2.0, + "minimum": 1.2, + "type": "number" + }, + "mesher": { + "title": "Grid Construction Tool", + "description": "The type of mesher to use to generate the grid automatically.", + "default": { + "attrs": {}, + "type": "GradedMesher" + }, + "allOf": [ + { + "$ref": "#/definitions/GradedMesher" + } + ] + }, + "dl_min": { + "title": "Lower Bound of Grid Size", + "description": "Lower bound of the grid size along this dimension regardless of structures present in the simulation, including override structures with ``enforced=True``. It is a soft bound, meaning that the actual minimal grid size might be slightly smaller. If ``None`` or 0, a heuristic lower bound value will be applied.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for quasi-uniform grid generation. Grid size at some locations can be slightly smaller.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "MeshOverrideStructure": { + "title": "MeshOverrideStructure", + "description": "Defines an object that is only used in the process of generating the mesh.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngeometry : Union[Box, Transformed, ClipOperation, GeometryGroup, Sphere, Cylinder, PolySlab, ComplexPolySlabBase, TriangleMesh]\n Defines geometric properties of the structure.\nname : Optional[str] = None\n Optional name for the structure.\nbackground_permittivity : Optional[ConstrainedFloatValue] = None\n DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.\nbackground_medium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = None\n Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.\npriority : int = 0\n Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.\ndl : Tuple[PositiveFloat, PositiveFloat, PositiveFloat]\n [units = um]. Grid size along x, y, z directions.\nenforce : bool = False\n If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.\nshadow : bool = True\n In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.\ndrop_outside_sim : bool = True\n If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.\n\nNotes\n-----\n\n A :class:`MeshOverrideStructure` is a combination of geometry :class:`Geometry`,\n grid size along ``x``, ``y``, ``z`` directions, and a boolean on whether the override\n will be enforced.\n\nExample\n-------\n>>> from tidy3d import Box\n>>> box = Box(center=(0,0,1), size=(2, 2, 2))\n>>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box')", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "geometry": { + "title": "Geometry", + "description": "Defines geometric properties of the structure.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "Transformed": "#/definitions/Transformed", + "ClipOperation": "#/definitions/ClipOperation", + "GeometryGroup": "#/definitions/GeometryGroup", + "Sphere": "#/definitions/Sphere", + "Cylinder": "#/definitions/Cylinder", + "PolySlab": "#/definitions/PolySlab", + "ComplexPolySlabBase": "#/definitions/ComplexPolySlabBase", + "TriangleMesh": "#/definitions/TriangleMesh" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/Transformed" + }, + { + "$ref": "#/definitions/ClipOperation" + }, + { + "$ref": "#/definitions/GeometryGroup" + }, + { + "$ref": "#/definitions/Sphere" + }, + { + "$ref": "#/definitions/Cylinder" + }, + { + "$ref": "#/definitions/PolySlab" + }, + { + "$ref": "#/definitions/ComplexPolySlabBase" + }, + { + "$ref": "#/definitions/TriangleMesh" + } + ] + }, + "name": { + "title": "Name", + "description": "Optional name for the structure.", + "type": "string" + }, + "background_permittivity": { + "title": "Background Permittivity", + "description": "DEPRECATED: Use ``Structure.background_medium``. Relative permittivity used for the background of this structure when performing shape optimization with autograd.", + "minimum": 1.0, + "type": "number" + }, + "background_medium": { + "title": "Background Medium", + "description": "Medium used for the background of this structure when performing shape optimization with autograd. This is required when the structure is embedded in another structure as autograd will use the permittivity of the ``Simulation`` by default to compute the shape derivatives.", + "anyOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "priority": { + "title": "Priority", + "description": "Priority of the structure applied in mesh override structure overlapping region. The priority of internal override structures is ``-1``.", + "default": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "MeshOverrideStructure", + "enum": [ + "MeshOverrideStructure" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size along x, y, z directions.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "number", + "exclusiveMinimum": 0 + } + ] + }, + "enforce": { + "title": "Enforce Grid Size", + "description": "If ``True``, enforce the grid size setup inside the structure even if the structure is inside a structure of smaller grid size. In the intersection region of multiple structures of ``enforce=True``, grid size is decided by the last added structure of ``enforce=True``.", + "default": false, + "type": "boolean" + }, + "shadow": { + "title": "Grid Size Choice In Structure Overlapping Region", + "description": "In structure intersection region, grid size is decided by the latter added structure in the structure list when ``shadow=True``; or the structure of smaller grid size when ``shadow=False``. If ``shadow=False``, and the structure doesn't refine the mesh, grid snapping to the bounding box of the structure is disabled.", + "default": true, + "type": "boolean" + }, + "drop_outside_sim": { + "title": "Drop Structure Outside Simulation Domain", + "description": "If ``True``, structure outside the simulation domain is dropped; if ``False``, structure takes effect along the dimensions where the projections of the structure and that of the simulation domain overlap.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "geometry", + "dl" + ], + "additionalProperties": false + }, + "GridRefinement": { + "title": "GridRefinement", + "description": "Specification for local mesh refinement that defines the grid step size and the number of grid\ncells in the refinement region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrefinement_factor : Optional[PositiveFloat] = None\n Refine grid step size in vacuum by this factor.\ndl : Optional[PositiveFloat] = None\n [units = um]. Grid step size in the refined region.\nnum_cells : PositiveInt = 3\n Number of grid cells in the refinement region.\n\nNote\n----\n\nIf both `refinement_factor` and `dl` are defined, the grid step size is upper bounded by the smaller value of the two.\nIf neither is defined, default `refinement_factor=2` is applied.\n\n\nExample\n-------\n>>> grid_refine = GridRefinement(refinement_factor = 2, num_cells = 7)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "refinement_factor": { + "title": "Mesh Refinement Factor", + "description": "Refine grid step size in vacuum by this factor.", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl": { + "title": "Grid Size", + "description": "Grid step size in the refined region.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_cells": { + "title": "Number of Refined Grid Cells", + "description": "Number of grid cells in the refinement region.", + "default": 3, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "GridRefinement", + "enum": [ + "GridRefinement" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "CornerFinderSpec": { + "title": "CornerFinderSpec", + "description": "Specification for corner detection on a 2D plane.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmedium : Literal['metal', 'dielectric', 'all'] = metal\n Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.\nangle_threshold : ConstrainedFloatValue = 0.3141592653589793\n A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.\ndistance_threshold : Optional[PositiveFloat] = None\n If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.\nconcave_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nconvex_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.\nmixed_resolution : Optional[PositiveInt] = None\n Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "medium": { + "title": "Material Type For Corner Identification", + "description": "Find corners of structures made of ``medium``, which can take value ``metal`` for PEC and lossy metal, ``dielectric`` for non-metallic materials, and ``all`` for all materials.", + "default": "metal", + "enum": [ + "metal", + "dielectric", + "all" + ], + "type": "string" + }, + "angle_threshold": { + "title": "Angle Threshold In Corner Identification", + "description": "A vertex is qualified as a corner if the angle spanned by its two edges is larger than the supplementary angle of this threshold value.", + "default": 0.3141592653589793, + "exclusiveMaximum": 3.141592653589793, + "minimum": 0, + "type": "number" + }, + "distance_threshold": { + "title": "Distance Threshold In Corner Identification", + "description": "If not ``None`` and the distance of the vertex to its neighboring vertices is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.", + "exclusiveMinimum": 0, + "type": "number" + }, + "concave_resolution": { + "title": "Concave Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on concave featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "convex_resolution": { + "title": "Convex Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on convex featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mixed_resolution": { + "title": "Mixed Region Resolution.", + "description": "Specifies number of steps to use for determining `dl_min` based on mixed featues.If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "CornerFinderSpec", + "enum": [ + "CornerFinderSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LayerRefinementSpec": { + "title": "LayerRefinementSpec", + "description": "Specification for automatic mesh refinement and snapping in layered structures. Structure corners\non the cross section perpendicular to layer thickness direction can be automatically identified. Subsequently,\nmesh is snapped and refined around the corners. Mesh can also be refined and snapped around the bounds along\nthe layer thickness direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\naxis : Literal[0, 1, 2]\n Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).\nmin_steps_along_axis : Optional[PositiveFloat] = None\n If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.\nbounds_refinement : Optional[GridRefinement] = None\n If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.\nbounds_snapping : Optional[Literal['bounds', 'lower', 'upper', 'center']] = lower\n If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.\ncorner_finder : Optional[CornerFinderSpec] = CornerFinderSpec(attrs={}, medium='metal', angle_threshold=0.3141592653589793, distance_threshold=None, concave_resolution=None, convex_resolution=None, mixed_resolution=None, type='CornerFinderSpec')\n Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.\ncorner_snapping : bool = True\n If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.\ncorner_refinement : Optional[GridRefinement] = GridRefinement(attrs={}, refinement_factor=None, dl=None, num_cells=3, type='GridRefinement')\n If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. \nrefinement_inside_sim_only : bool = True\n If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.\ngap_meshing_iters : NonNegativeInt = 1\n Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.\ndl_min_from_gap_width : bool = True\n Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.\n\nNote\n----\n\nCorner detection is performed on a 2D plane sitting in the middle of the layer. If the layer is finite\nalong inplane axes, corners outside the bounds are discarded.\n\nNote\n----\n\nThis class only takes effect when :class:`AutoGrid` is applied.\n\nExample\n-------\n>>> layer_spec = LayerRefinementSpec(axis=2, center=(0,0,0), size=(2, 3, 1))", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LayerRefinementSpec", + "enum": [ + "LayerRefinementSpec" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the layer normal axis (0,1,2) -> (x,y,z).", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "min_steps_along_axis": { + "title": "Minimal Number Of Steps Along Axis", + "description": "If not ``None`` and the thickness of the layer is nonzero, set minimal number of steps discretizing the layer thickness.", + "exclusiveMinimum": 0, + "type": "number" + }, + "bounds_refinement": { + "title": "Mesh Refinement Factor Around Layer Bounds", + "description": "If not ``None``, refine mesh around minimum and maximum positions of the layer along normal axis dimension. If `min_steps_along_axis` is also specified, refinement here is only applied if it sets a smaller grid size.", + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "bounds_snapping": { + "title": "Placing Grid Snapping Point Along Axis", + "description": "If not ``None``, enforcing grid boundaries to pass through ``lower``, ``center``, or ``upper`` position of the layer; or both ``lower`` and ``upper`` with ``bounds``.", + "default": "lower", + "enum": [ + "bounds", + "lower", + "upper", + "center" + ], + "type": "string" + }, + "corner_finder": { + "title": "Inplane Corner Detection Specification", + "description": "Specification for inplane corner detection. Inplane mesh refinement is based on the coordinates of those corners.", + "default": { + "attrs": {}, + "medium": "metal", + "angle_threshold": 0.3141592653589793, + "distance_threshold": null, + "concave_resolution": null, + "convex_resolution": null, + "mixed_resolution": null, + "type": "CornerFinderSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/CornerFinderSpec" + } + ] + }, + "corner_snapping": { + "title": "Placing Grid Snapping Point At Corners", + "description": "If ``True`` and ``corner_finder`` is not ``None``, enforcing inplane grid boundaries to pass through corners of geometries specified by ``corner_finder``.", + "default": true, + "type": "boolean" + }, + "corner_refinement": { + "title": "Inplane Mesh Refinement Factor Around Corners", + "description": "If not ``None`` and ``corner_finder`` is not ``None``, refine mesh around corners of geometries specified by ``corner_finder``. ", + "default": { + "attrs": {}, + "refinement_factor": null, + "dl": null, + "num_cells": 3, + "type": "GridRefinement" + }, + "allOf": [ + { + "$ref": "#/definitions/GridRefinement" + } + ] + }, + "refinement_inside_sim_only": { + "title": "Apply Refinement Only To Features Inside Simulation Domain", + "description": "If ``True``, only apply mesh refinement to features such as corners inside the simulation domain; If ``False``, features outside the domain can take effect along the dimensions where the projection of the feature and the projection of the simulation domain overlaps.", + "default": true, + "type": "boolean" + }, + "gap_meshing_iters": { + "title": "Gap Meshing Iterations", + "description": "Number of recursive iterations for resolving thin gaps. The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "dl_min_from_gap_width": { + "title": "Set ``dl_min`` from Estimated Gap Width", + "description": "Take into account autodetected minimal PEC gap width when determining ``dl_min``. This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.", + "default": true, + "type": "boolean" + } + }, + "required": [ + "size", + "axis" + ], + "additionalProperties": false + }, + "GridSpec": { + "title": "GridSpec", + "description": "Collective grid specification for all three dimensions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ngrid_x : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along x-axis\ngrid_y : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along y-axis\ngrid_z : Union[UniformGrid, CustomGrid, AutoGrid, CustomGridBoundaries, QuasiUniformGrid] = AutoGrid(attrs={}, type='AutoGrid', max_scale=1.4, mesher=GradedMesher(attrs={},, type='GradedMesher'), dl_min=None, min_steps_per_wvl=10.0, min_steps_per_sim_size=10.0)\n Grid specification along z-axis\nwavelength : Optional[float] = None\n [units = um]. Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.\noverride_structures : Tuple[Annotated[Union[tidy3d.components.structure.Structure, tidy3d.components.structure.MeshOverrideStructure], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nsnapping_points : Tuple[tuple[Optional[float], Optional[float], Optional[float]], ...] = ()\n A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.\nlayer_refinement_specs : Tuple[LayerRefinementSpec, ...] = ()\n Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.\n\nExample\n-------\n>>> uniform = UniformGrid(dl=0.1)\n>>> custom = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2])\n>>> auto = AutoGrid(min_steps_per_wvl=12)\n>>> grid_spec = GridSpec(grid_x=uniform, grid_y=custom, grid_z=auto, wavelength=1.5)\n\nSee Also\n--------\n\n:class:`UniformGrid`\n Uniform 1D grid.\n\n:class:`AutoGrid`\n Specification for non-uniform grid along a given dimension.\n\n**Notebooks:**\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n\n**Lectures:**\n * `Time step size and CFL condition in FDTD `_\n * `Numerical dispersion in FDTD `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "grid_x": { + "title": "Grid specification along x-axis", + "description": "Grid specification along x-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_y": { + "title": "Grid specification along y-axis", + "description": "Grid specification along y-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "grid_z": { + "title": "Grid specification along z-axis", + "description": "Grid specification along z-axis", + "default": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformGrid": "#/definitions/UniformGrid", + "CustomGrid": "#/definitions/CustomGrid", + "AutoGrid": "#/definitions/AutoGrid", + "CustomGridBoundaries": "#/definitions/CustomGridBoundaries", + "QuasiUniformGrid": "#/definitions/QuasiUniformGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformGrid" + }, + { + "$ref": "#/definitions/CustomGrid" + }, + { + "$ref": "#/definitions/AutoGrid" + }, + { + "$ref": "#/definitions/CustomGridBoundaries" + }, + { + "$ref": "#/definitions/QuasiUniformGrid" + } + ] + }, + "wavelength": { + "title": "Free-space wavelength", + "description": "Free-space wavelength for automatic nonuniform grid. It can be 'None' if there is at least one source in the simulation, in which case it is defined by the source central frequency. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid`.", + "units": "um", + "type": "number" + }, + "override_structures": { + "title": "Grid specification override structures", + "description": "A set of structures that is added on top of the simulation structures in the process of generating the grid. This can be used to refine the grid or make it coarser depending than the expected need for higher/lower resolution regions. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Structure": "#/definitions/Structure", + "MeshOverrideStructure": "#/definitions/MeshOverrideStructure" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Structure" + }, + { + "$ref": "#/definitions/MeshOverrideStructure" + } + ] + } + }, + "snapping_points": { + "title": "Grid specification snapping_points", + "description": "A set of points that enforce grid boundaries to pass through them. However, some points might be skipped if they are too close. When points are very close to `override_structures`, `snapping_points` have higher prioirty so that the structures might be skipped. Note: it only takes effect when at least one of the three dimensions uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", + "default": [], + "type": "array", + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + } + }, + "layer_refinement_specs": { + "title": "Mesh Refinement In Layered Structures", + "description": "Automatic mesh refinement according to layer specifications. The material distribution is assumed to be uniform inside the layer along the layer axis. Mesh can be refined around corners on the layer cross section, and around upper and lower bounds of the layer.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/LayerRefinementSpec" + } + }, + "type": { + "title": "Type", + "default": "GridSpec", + "enum": [ + "GridSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "LumpedResistor": { + "title": "LumpedResistor", + "description": "Class representing a rectangular lumped resistor. Lumped resistors are appended to the list\nof structures in the simulation as :class:`Medium2D` with the appropriate conductivity given\ntheir size and voltage axis.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nresistance : PositiveFloat\n Resistance value in ohms.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LumpedResistor", + "enum": [ + "LumpedResistor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "resistance" + ], + "additionalProperties": false + }, + "CoaxialLumpedResistor": { + "title": "CoaxialLumpedResistor", + "description": "Class representing a coaxial lumped resistor. Lumped resistors are appended to the list of\nstructures in the simulation as :class:`Medium2D` with the appropriate conductivity given their\nsize and geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nresistance : PositiveFloat\n Resistance value in ohms.\ncenter : Tuple[float, float, float] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nouter_diameter : PositiveFloat\n [units = um]. Diameter of the outer concentric circle.\ninner_diameter : PositiveFloat\n [units = um]. Diameter of the inner concentric circle.\nnormal_axis : Literal[0, 1, 2]\n Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "CoaxialLumpedResistor", + "enum": [ + "CoaxialLumpedResistor" + ], + "type": "string" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "outer_diameter": { + "title": "Outer Diameter", + "description": "Diameter of the outer concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "inner_diameter": { + "title": "Inner Diameter", + "description": "Diameter of the inner concentric circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "normal_axis": { + "title": "Normal Axis", + "description": "Specifies the normal axis, which defines the orientation of the circles making up the coaxial lumped element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + } + }, + "required": [ + "name", + "resistance", + "outer_diameter", + "inner_diameter", + "normal_axis" + ], + "additionalProperties": false + }, + "RLCNetwork": { + "title": "RLCNetwork", + "description": "Class for representing a simple network consisting of a resistor, capacitor, and inductor.\nProvides additional functionality for representing the network as an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nresistance : Optional[PositiveFloat] = None\n Resistance value in ohms.\ncapacitance : Optional[PositiveFloat] = None\n Capacitance value in farads.\ninductance : Optional[PositiveFloat] = None\n Inductance value in henrys.\nnetwork_topology : Literal['series', 'parallel'] = series\n Describes whether network elements are connected in ``series`` or ``parallel``.\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "resistance": { + "title": "Resistance", + "description": "Resistance value in ohms.", + "unit": "ohm", + "exclusiveMinimum": 0, + "type": "number" + }, + "capacitance": { + "title": "Capacitance", + "description": "Capacitance value in farads.", + "unit": "farad", + "exclusiveMinimum": 0, + "type": "number" + }, + "inductance": { + "title": "Inductance", + "description": "Inductance value in henrys.", + "unit": "henry", + "exclusiveMinimum": 0, + "type": "number" + }, + "network_topology": { + "title": "Network Topology", + "description": "Describes whether network elements are connected in ``series`` or ``parallel``.", + "default": "series", + "enum": [ + "series", + "parallel" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "RLCNetwork", + "enum": [ + "RLCNetwork" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "AdmittanceNetwork": { + "title": "AdmittanceNetwork", + "description": "Class for representing a network consisting of an arbitrary number of resistors,\ncapacitors, and inductors. The network is represented in the Laplace domain\nas an admittance function. Provides additional functionality for representing the network\nas an equivalent medium.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\na : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.\nb : Tuple[NonNegativeFloat, ...]\n A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.\n\nNotes\n-----\n\n The network is described by the supplied coefficients as an admittance function that relates\n voltage to the current in the Laplace domain and is equivalent to a frequency-dependent\n complex conductivity :math:`\\sigma(\\omega)`.\n\n .. math::\n I(s) = Y(s)V(s)\n\n .. math::\n Y(s) = \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}\n\n An equivalent :class:`.PoleResidue` medium is constructed using an equivalent frequency-dependent\n complex permittivity defined as\n\n .. math::\n \\epsilon(s) = \\epsilon_\\infty - \\frac{\\Delta}{\\epsilon_0 s}\n \\frac{a_0 + a_1 s + \\dots + a_M s^M}{b_0 + b_1 s + \\dots + b_N s^N}.\n\n The admittance is scaled depending on the geometric properties of the lumped element by\n the scaling factor :math:`\\Delta`. Implementation is based on the equivalent medium introduced\n by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> R = 50\n>>> C = 1e-12\n>>> a = (1, R * C) # Coefficients for an RC parallel network\n>>> b = (R, 0)\n>>> RC_parallel = AdmittanceNetwork(a=a,\n... b=b\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "a": { + "title": "Numerator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the numerator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "b": { + "title": "Denominator Coefficients", + "description": "A ``tuple`` of floats describing the coefficients of the denomiator polynomial. The length of the ``tuple`` is equal to the order of the network.", + "type": "array", + "items": { + "type": "number", + "minimum": 0 + } + }, + "type": { + "title": "Type", + "default": "AdmittanceNetwork", + "enum": [ + "AdmittanceNetwork" + ], + "type": "string" + } + }, + "required": [ + "a", + "b" + ], + "additionalProperties": false + }, + "LinearLumpedElement": { + "title": "LinearLumpedElement", + "description": "Lumped element representing a network consisting of resistors, capacitors, and inductors.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the lumped element.\nnum_grid_cells : Optional[PositiveInt] = 1\n Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.\nnetwork : Union[RLCNetwork, AdmittanceNetwork]\n The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Switches between the different methods for distributing the lumped element over the grid.\n\n\n\nNotes\n-----\n\n Implementation is based on the equivalent medium introduced by _`[1]`.\n\n **References**\n\n .. [1] J. A. Pereda, F. Alimenti, P. Mezzanotte, L. Roselli and R. Sorrentino, \"A new algorithm\n for the incorporation of arbitrary linear lumped networks into FDTD simulators,\" IEEE\n Trans. Microw. Theory Tech., vol. 47, no. 6, pp. 943-949, Jun. 1999.\n\nExample\n-------\n>>> RL_series = RLCNetwork(resistance=75,\n... inductance=1e-9,\n... network_topology=\"series\"\n... ) # doctest: +SKIP\n>>> linear_element = LinearLumpedElement(\n... center=[0, 0, 0],\n... size=[2, 0, 3],\n... voltage_axis=0,\n... network=RL_series,\n... name=\"LumpedRL\"\n... ) # doctest: +SKIP\n\n\nSee Also\n--------\n\n**Notebooks:**\n * `Using lumped elements in Tidy3D simulations <../../notebooks/LinearLumpedElements.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LinearLumpedElement", + "enum": [ + "LinearLumpedElement" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the lumped element.", + "minLength": 1, + "type": "string" + }, + "num_grid_cells": { + "title": "Lumped element grid cells", + "description": "Number of mesh grid cells associated with the lumped element along each direction. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. A value of ``None`` will turn off mesh refinement suggestions.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Element", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped element for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Drop Axis", + "description": "Specifies the axis along which the component is oriented and along which the associated voltage drop will occur. Must be in the plane of the element.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the lumped element is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. Sides of the element perpendicular to the ``voltage_axis`` are snapped to grid boundaries, while the sides parallel to the ``voltage_axis`` are snapped to grid centers. Lumped elements are always snapped to the nearest grid boundary along their ``normal_axis``, regardless of this option.", + "default": true, + "type": "boolean" + }, + "network": { + "title": "Network", + "description": "The linear element produces an equivalent medium that emulates the voltage-current relationship described by the ``network`` field.", + "discriminator": { + "propertyName": "type", + "mapping": { + "RLCNetwork": "#/definitions/RLCNetwork", + "AdmittanceNetwork": "#/definitions/AdmittanceNetwork" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/RLCNetwork" + }, + { + "$ref": "#/definitions/AdmittanceNetwork" + } + ] + }, + "dist_type": { + "title": "Distribute Type", + "description": "Switches between the different methods for distributing the lumped element over the grid.", + "default": "on", + "enum": [ + "off", + "laterally_only", + "on" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "voltage_axis", + "network" + ], + "additionalProperties": false + }, + "Staircasing": { + "title": "Staircasing", + "description": "Apply staircasing scheme to material assignment of Yee grids on structure boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nFor PEC interface, the algorithm is based on:\n\n A. Taflove and S. C. Hagness, \"Computational electromagnetics: the\n finite-difference time-domain method\", Chapter 10.3 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Staircasing", + "enum": [ + "Staircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PolarizedAveraging": { + "title": "PolarizedAveraging", + "description": "Apply a polarized subpixel averaging method to dielectric boundaries, which\nis a phenomenological approximation of :class:`.ContourPathAveraging`.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PolarizedAveraging", + "enum": [ + "PolarizedAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "ContourPathAveraging": { + "title": "ContourPathAveraging", + "description": "Apply a contour-path subpixel averaging method to dielectric boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNote\n----\nThe algorithm is based on:\n\n A. Mohammadi, H. Nadgaran and M. Agio, \"Contour-path effective\n permittivities for the two-dimensional finite-difference\n time-domain method\", Optics express, 13(25), 10367-10381 (2005).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ContourPathAveraging", + "enum": [ + "ContourPathAveraging" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "VolumetricAveraging": { + "title": "VolumetricAveraging", + "description": "Apply volumetric averaging scheme to material properties of Yee grids on structure boundaries.\nThe material property is averaged in the volume surrounding the Yee grid.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstaircase_normal_component : bool = True\n Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VolumetricAveraging", + "enum": [ + "VolumetricAveraging" + ], + "type": "string" + }, + "staircase_normal_component": { + "title": "Staircasing For Field Components Substantially Normal To Interface", + "description": "Volumetric averaging works accurately if the electric field component is substantially tangential to the interface. If ``True``, apply volumetric averaging only if the field component is largely tangential to the interface; if ``False``, apply volumetric averaging regardless of how field component orients with the interface.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "HeuristicPECStaircasing": { + "title": "HeuristicPECStaircasing", + "description": "Apply a variant of staircasing scheme to PEC boundaries: the electric field grid is set to PEC\nif the field is substantially parallel to the interface.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeuristicPECStaircasing", + "enum": [ + "HeuristicPECStaircasing" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "PECConformal": { + "title": "PECConformal", + "description": "Apply a subpixel averaging method known as conformal mesh scheme to PEC boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.3\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.\n\nNote\n----\nThe algorithm is based on:\n\n S. Dey and R. Mittra, \"A locally conformal finite-difference\n time-domain (FDTD) algorithm for modeling three-dimensional\n perfectly conducting objects\",\n IEEE Microwave and Guided Wave Letters, 7(9), 273 (1997).\n\n S. Benkler, N. Chavannes and N. Kuster, \"A new 3-D conformal\n PEC FDTD scheme with user-defined geometric precision and derived\n stability criterion\",\n IEEE Transactions on Antennas and Propagation, 54(6), 1843 (2006).", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "PECConformal", + "enum": [ + "PECConformal" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.3, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SurfaceImpedance": { + "title": "SurfaceImpedance", + "description": "Apply 1st order (Leontovich) surface impedance boundary condition to\nstructure made of :class:`.LossyMetalMedium`.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntimestep_reduction : ConstrainedFloatValue = 0.0\n Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.\nedge_singularity_correction : bool = False\n Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SurfaceImpedance", + "enum": [ + "SurfaceImpedance" + ], + "type": "string" + }, + "timestep_reduction": { + "title": "Time Step Size Reduction Rate", + "description": "Reduction factor between 0 and 1 such that the simulation's time step size is ``1 - timestep_reduction`` times its default value. Accuracy can be improved with a smaller time step size, but the simulation time will be increased.", + "default": 0.0, + "exclusiveMaximum": 1, + "minimum": 0, + "type": "number" + }, + "edge_singularity_correction": { + "title": "Apply Singularity Model At Metal Edges", + "description": "Apply field correction model at metallic edges where field singularity occurs. The edges should be straight, and aligned with the primal grids; and the wedge angle is either 0 or 90 degree.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "SubpixelSpec": { + "title": "SubpixelSpec", + "description": "Defines specification for subpixel averaging schemes when added to ``Simulation.subpixel``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ndielectric : Union[Staircasing, PolarizedAveraging, ContourPathAveraging] = PolarizedAveraging(attrs={}, type='PolarizedAveraging')\n Subpixel averaging method applied to dielectric material interfaces.\nmetal : Union[Staircasing, VolumetricAveraging] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.\npec : Union[Staircasing, HeuristicPECStaircasing, PECConformal] = PECConformal(attrs={}, type='PECConformal', timestep_reduction=0.3, edge_singularity_correction=False)\n Subpixel averaging method applied to PEC structure interfaces.\npmc : Union[Staircasing, HeuristicPECStaircasing] = Staircasing(attrs={}, type='Staircasing')\n Subpixel averaging method applied to PMC structure interfaces.\nlossy_metal : Union[Staircasing, VolumetricAveraging, SurfaceImpedance] = SurfaceImpedance(attrs={}, type='SurfaceImpedance', timestep_reduction=0.0, edge_singularity_correction=False)\n Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "dielectric": { + "title": "Subpixel Averaging Method For Dielectric Interfaces", + "description": "Subpixel averaging method applied to dielectric material interfaces.", + "default": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "PolarizedAveraging": "#/definitions/PolarizedAveraging", + "ContourPathAveraging": "#/definitions/ContourPathAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/PolarizedAveraging" + }, + { + "$ref": "#/definitions/ContourPathAveraging" + } + ] + }, + "metal": { + "title": "Subpixel Averaging Method For Metallic Interfaces", + "description": "Subpixel averaging method applied to metallic structure interfaces. A material is considered as metallic if its real part of relative permittivity is less than 1 at the central frequency.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + } + ] + }, + "pec": { + "title": "Subpixel Averaging Method For PEC Interfaces", + "description": "Subpixel averaging method applied to PEC structure interfaces.", + "default": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing", + "PECConformal": "#/definitions/PECConformal" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + }, + { + "$ref": "#/definitions/PECConformal" + } + ] + }, + "pmc": { + "title": "Subpixel Averaging Method For PMC Interfaces", + "description": "Subpixel averaging method applied to PMC structure interfaces.", + "default": { + "attrs": {}, + "type": "Staircasing" + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "HeuristicPECStaircasing": "#/definitions/HeuristicPECStaircasing" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/HeuristicPECStaircasing" + } + ] + }, + "lossy_metal": { + "title": "Subpixel Averaging Method for Lossy Metal Interfaces", + "description": "Subpixel averaging method applied to ``td.LossyMetalMedium`` material interfaces.", + "default": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Staircasing": "#/definitions/Staircasing", + "VolumetricAveraging": "#/definitions/VolumetricAveraging", + "SurfaceImpedance": "#/definitions/SurfaceImpedance" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Staircasing" + }, + { + "$ref": "#/definitions/VolumetricAveraging" + }, + { + "$ref": "#/definitions/SurfaceImpedance" + } + ] + }, + "type": { + "title": "Type", + "default": "SubpixelSpec", + "enum": [ + "SubpixelSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "RunTimeSpec": { + "title": "RunTimeSpec", + "description": "Defines specification for how long to run a simulation when added to ``Simulation.run_time``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nquality_factor : PositiveFloat\n Quality factor expected in the device. This determines how long the simulation will run as it assumes a field decay time that scales proportionally to this value.\nsource_factor : PositiveFloat = 3\n The contribution to the ``run_time`` from the longest source is computed from the ``source_time`` length times ``source_factor``. Larger values provide more buffer at the expense of potentially giving ``run_time`` values that are larger than needed.\n\nNotes\n-----\n\n The evaluated ``run_time`` will be computed from a ``RunTimeSpec()`` as follows:\n\n .. math::\n\n \\text{run_time} = \\text{source_factor} * T_{src_max} + \\text{quality_factor} n_{max} L_{max} / c_{0}\n\n Where: ``source_factor`` and ``quality_factor`` are fields in the spec,\n :math:`T_{src_max}` is the longest time that a source is non-zero,\n :math:`n_{max}` is the maximum refractive index in the simulation,\n :math:`L_{max}` is the distance along the largest dimension in the simulation, and\n :math:`c_0` is the speed of light in vacuum.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "quality_factor": { + "title": "Quality Factor", + "description": "Quality factor expected in the device. This determines how long the simulation will run as it assumes a field decay time that scales proportionally to this value.", + "exclusiveMinimum": 0, + "type": "number" + }, + "source_factor": { + "title": "Source Factor", + "description": "The contribution to the ``run_time`` from the longest source is computed from the ``source_time`` length times ``source_factor``. Larger values provide more buffer at the expense of potentially giving ``run_time`` values that are larger than needed.", + "default": 3, + "exclusiveMinimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "RunTimeSpec", + "enum": [ + "RunTimeSpec" + ], + "type": "string" + } + }, + "required": [ + "quality_factor" + ], + "additionalProperties": false + }, + "Simulation": { + "title": "Simulation", + "description": "Custom implementation of Maxwell\u2019s equations which represents the physical model to be solved using the FDTD\nmethod.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (no symmetry), ``1`` (even, i.e. 'PMC' symmetry) or ``-1`` (odd, i.e. 'PEC' symmetry). Note that the vectorial nature of the fields must be taken into account to correctly determine the symmetry value.\nsources : Tuple[Annotated[Union[tidy3d.components.source.current.UniformCurrentSource, tidy3d.components.source.current.PointDipole, tidy3d.components.source.field.GaussianBeam, tidy3d.components.source.field.AstigmaticGaussianBeam, tidy3d.components.source.field.ModeSource, tidy3d.components.source.field.PlaneWave, tidy3d.components.source.field.CustomFieldSource, tidy3d.components.source.current.CustomCurrentSource, tidy3d.components.source.field.TFSF], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of electric current sources injecting fields into the simulation.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), y=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), z=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides.\nmonitors : Tuple[Annotated[Union[tidy3d.components.monitor.FieldMonitor, tidy3d.components.monitor.FieldTimeMonitor, tidy3d.components.monitor.AuxFieldTimeMonitor, tidy3d.components.monitor.PermittivityMonitor, tidy3d.components.monitor.FluxMonitor, tidy3d.components.monitor.FluxTimeMonitor, tidy3d.components.monitor.ModeMonitor, tidy3d.components.monitor.ModeSolverMonitor, tidy3d.components.monitor.FieldProjectionAngleMonitor, tidy3d.components.monitor.FieldProjectionCartesianMonitor, tidy3d.components.monitor.FieldProjectionKSpaceMonitor, tidy3d.components.monitor.DiffractionMonitor, tidy3d.components.monitor.DirectivityMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. \nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\ncourant : ConstrainedFloatValue = 0.99\n Normalized Courant stability factor that is no larger than 1 when CFL stability condition is met. It controls time step to spatial step ratio. Lower values lead to more stable simulations for dispersive materials, but result in longer simulation times.\nprecision : Literal['hybrid', 'double'] = hybrid\n Floating point precision to use in the computations. By default, Tidy3D uses a hybrid approach that offers a good balance of speed and accuracy for almost all simulations. However, for large simulations (or simulations with a long run time), where very high accuracy is needed, the precision can be set to double everywhere. Note that this doubles the FlexCredit cost of the simulation.\nnormalize_index : Optional[NonNegativeInt] = 0\n Index of the source in the tuple of sources whose spectrum will be used to normalize the frequency-dependent data. If ``None``, the raw field data is returned unnormalized.\nshutoff : NonNegativeFloat = 1e-05\n Ratio of the instantaneous integrated E-field intensity to the maximum value at which the simulation will automatically terminate time stepping. Used to prevent extraneous run time of simulations with fully decayed fields. Set to ``0`` to disable this feature.\nrun_time : Union[PositiveFloat, RunTimeSpec]\n [units = sec]. Total electromagnetic evolution time in seconds. Note: If simulation 'shutoff' is specified, simulation will terminate early when shutoff condition met. Alternatively, user may supply a :class:`RunTimeSpec` to this field, which will auto-compute the ``run_time`` based on the contents of the spec. If this option is used, the evaluated ``run_time`` value is available in the ``Simulation._run_time`` property.\n\nNotes\n-----\n\n A ``Simulation`` defines a custom implementation of Maxwell's equations which represents the physical model\n to be solved using `the Finite-Difference Time-Domain (FDTD) method\n `_. ``tidy3d`` simulations\n run very quickly in the cloud through GPU parallelization.\n\n .. image:: ../../_static/img/field_update_fdtd.png\n :width: 50%\n :align: left\n\n FDTD is a method for simulating the interaction of electromagnetic waves with structures and materials. It is\n the most widely used method in photonics design. The Maxwell's\n equations implemented in the ``Simulation`` are solved per time-step in the order shown in this image.\n\n The simplified input to FDTD solver consists of the permittivity distribution defined by :attr:`structures`\n which describe the device and :attr:`sources` of electromagnetic excitation. This information is used to\n computate the time dynamics of the electric and magnetic fields in this system. From these time-domain\n results, frequency-domain information of the simulation can also be extracted, and used for device design and\n optimization.\n\n If you are new to the FDTD method, we recommend you get started with the `FDTD 101 Lecture Series\n `_\n\n **Dimensions Selection**\n\n By default, simulations are defined as 3D. To make the simulation 2D, we can just set the simulation\n :attr:`size` in one of the dimensions to be 0. However, note that we still have to define a grid size (eg.\n ``tidy3d.Simulation(size=[size_x, size_y, 0])``) and specify a periodic boundary condition in that direction.\n\n .. TODO sort out inheritance problem https://aware-moon.cloudvent.net/tidy3d/examples/notebooks/RingResonator/\n\n See further parameter explanations below.\n\nExample\n-------\n>>> from tidy3d import Sphere, Cylinder, PolySlab\n>>> from tidy3d import UniformCurrentSource, GaussianPulse\n>>> from tidy3d import FieldMonitor, FluxMonitor\n>>> from tidy3d import GridSpec, AutoGrid\n>>> from tidy3d import BoundarySpec, Boundary\n>>> from tidy3d import Medium\n>>> sim = Simulation(\n... size=(3.0, 3.0, 3.0),\n... grid_spec=GridSpec(\n... grid_x = AutoGrid(min_steps_per_wvl = 20),\n... grid_y = AutoGrid(min_steps_per_wvl = 20),\n... grid_z = AutoGrid(min_steps_per_wvl = 20)\n... ),\n... run_time=40e-11,\n... structures=[\n... Structure(\n... geometry=Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=Medium(permittivity=2.0),\n... ),\n... ],\n... sources=[\n... UniformCurrentSource(\n... size=(0, 0, 0),\n... center=(0, 0.5, 0),\n... polarization=\"Hx\",\n... source_time=GaussianPulse(\n... freq0=2e14,\n... fwidth=4e13,\n... ),\n... )\n... ],\n... monitors=[\n... FluxMonitor(size=(1, 1, 0), center=(0, 0, 0), freqs=[2e14, 2.5e14], name='flux'),\n... ],\n... symmetry=(0, 0, 0),\n... boundary_spec=BoundarySpec(\n... x = Boundary.pml(num_layers=20),\n... y = Boundary.pml(num_layers=30),\n... z = Boundary.periodic(),\n... ),\n... shutoff=1e-6,\n... courant=0.8,\n... subpixel=False,\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `Quickstart <../../notebooks/StartHere.html>`_: Usage in a basic simulation flow.\n * `Using automatic nonuniform meshing <../../notebooks/AutoGrid.html>`_\n * See nearly all notebooks for :class:`Simulation` applications.\n\n**Lectures:**\n * `Introduction to FDTD Simulation `_: Usage in a basic simulation flow.\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_\n\n**GUI:**\n * `FDTD Walkthrough `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Simulation", + "enum": [ + "Simulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to vacuum if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (no symmetry), ``1`` (even, i.e. 'PMC' symmetry) or ``-1`` (odd, i.e. 'PEC' symmetry). Note that the vectorial nature of the fields must be taken into account to correctly determine the symmetry value.", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Sources", + "description": "Tuple of electric current sources injecting fields into the simulation.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformCurrentSource": "#/definitions/UniformCurrentSource", + "PointDipole": "#/definitions/PointDipole", + "GaussianBeam": "#/definitions/GaussianBeam", + "AstigmaticGaussianBeam": "#/definitions/AstigmaticGaussianBeam", + "ModeSource": "#/definitions/ModeSource", + "PlaneWave": "#/definitions/PlaneWave", + "CustomFieldSource": "#/definitions/CustomFieldSource", + "CustomCurrentSource": "#/definitions/CustomCurrentSource", + "TFSF": "#/definitions/TFSF" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformCurrentSource" + }, + { + "$ref": "#/definitions/PointDipole" + }, + { + "$ref": "#/definitions/GaussianBeam" + }, + { + "$ref": "#/definitions/AstigmaticGaussianBeam" + }, + { + "$ref": "#/definitions/ModeSource" + }, + { + "$ref": "#/definitions/PlaneWave" + }, + { + "$ref": "#/definitions/CustomFieldSource" + }, + { + "$ref": "#/definitions/CustomCurrentSource" + }, + { + "$ref": "#/definitions/TFSF" + } + ] + } + }, + "boundary_spec": { + "title": "Boundaries", + "description": "Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides.", + "default": { + "attrs": {}, + "x": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "y": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "z": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "type": "BoundarySpec" + }, + "allOf": [ + { + "$ref": "#/definitions/BoundarySpec" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "FieldMonitor": "#/definitions/FieldMonitor", + "FieldTimeMonitor": "#/definitions/FieldTimeMonitor", + "AuxFieldTimeMonitor": "#/definitions/AuxFieldTimeMonitor", + "PermittivityMonitor": "#/definitions/PermittivityMonitor", + "FluxMonitor": "#/definitions/FluxMonitor", + "FluxTimeMonitor": "#/definitions/FluxTimeMonitor", + "ModeMonitor": "#/definitions/ModeMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor", + "FieldProjectionAngleMonitor": "#/definitions/FieldProjectionAngleMonitor", + "FieldProjectionCartesianMonitor": "#/definitions/FieldProjectionCartesianMonitor", + "FieldProjectionKSpaceMonitor": "#/definitions/FieldProjectionKSpaceMonitor", + "DiffractionMonitor": "#/definitions/DiffractionMonitor", + "DirectivityMonitor": "#/definitions/DirectivityMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/FieldMonitor" + }, + { + "$ref": "#/definitions/FieldTimeMonitor" + }, + { + "$ref": "#/definitions/AuxFieldTimeMonitor" + }, + { + "$ref": "#/definitions/PermittivityMonitor" + }, + { + "$ref": "#/definitions/FluxMonitor" + }, + { + "$ref": "#/definitions/FluxTimeMonitor" + }, + { + "$ref": "#/definitions/ModeMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + }, + { + "$ref": "#/definitions/FieldProjectionAngleMonitor" + }, + { + "$ref": "#/definitions/FieldProjectionCartesianMonitor" + }, + { + "$ref": "#/definitions/FieldProjectionKSpaceMonitor" + }, + { + "$ref": "#/definitions/DiffractionMonitor" + }, + { + "$ref": "#/definitions/DirectivityMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Specifications for the simulation grid along each of the three directions.", + "default": { + "attrs": {}, + "grid_x": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_y": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_z": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "wavelength": null, + "override_structures": [], + "snapping_points": [], + "layer_refinement_specs": [], + "type": "GridSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/GridSpec" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "lumped_elements": { + "title": "Lumped Elements", + "description": "Tuple of lumped elements in the simulation. ", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "LumpedResistor": "#/definitions/LumpedResistor", + "CoaxialLumpedResistor": "#/definitions/CoaxialLumpedResistor", + "LinearLumpedElement": "#/definitions/LinearLumpedElement" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LumpedResistor" + }, + { + "$ref": "#/definitions/CoaxialLumpedResistor" + }, + { + "$ref": "#/definitions/LinearLumpedElement" + } + ] + } + }, + "subpixel": { + "title": "Subpixel Averaging", + "description": "Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.", + "default": { + "attrs": {}, + "dielectric": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "metal": { + "attrs": {}, + "type": "Staircasing" + }, + "pec": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" + }, + "lossy_metal": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "type": "SubpixelSpec" + }, + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/SubpixelSpec" + } + ] + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.", + "default": "tidy3d", + "enum": [ + "autograd_fwd", + "autograd_bwd", + "tidy3d" + ], + "type": "string" + }, + "post_norm": { + "title": "Post Normalization Values", + "description": "Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.", + "default": 1.0, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "courant": { + "title": "Normalized Courant Factor", + "description": "Normalized Courant stability factor that is no larger than 1 when CFL stability condition is met. It controls time step to spatial step ratio. Lower values lead to more stable simulations for dispersive materials, but result in longer simulation times.", + "default": 0.99, + "exclusiveMinimum": 0.0, + "maximum": 1.0, + "type": "number" + }, + "precision": { + "title": "Floating-point Precision", + "description": "Floating point precision to use in the computations. By default, Tidy3D uses a hybrid approach that offers a good balance of speed and accuracy for almost all simulations. However, for large simulations (or simulations with a long run time), where very high accuracy is needed, the precision can be set to double everywhere. Note that this doubles the FlexCredit cost of the simulation.", + "default": "hybrid", + "enum": [ + "hybrid", + "double" + ], + "type": "string" + }, + "normalize_index": { + "title": "Normalization index", + "description": "Index of the source in the tuple of sources whose spectrum will be used to normalize the frequency-dependent data. If ``None``, the raw field data is returned unnormalized.", + "default": 0, + "minimum": 0, + "type": "integer" + }, + "shutoff": { + "title": "Shutoff Condition", + "description": "Ratio of the instantaneous integrated E-field intensity to the maximum value at which the simulation will automatically terminate time stepping. Used to prevent extraneous run time of simulations with fully decayed fields. Set to ``0`` to disable this feature.", + "default": 1e-05, + "minimum": 0, + "type": "number" + }, + "run_time": { + "title": "Run Time", + "description": "Total electromagnetic evolution time in seconds. Note: If simulation 'shutoff' is specified, simulation will terminate early when shutoff condition met. Alternatively, user may supply a :class:`RunTimeSpec` to this field, which will auto-compute the ``run_time`` based on the contents of the spec. If this option is used, the evaluated ``run_time`` value is available in the ``Simulation._run_time`` property.", + "units": "sec", + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "$ref": "#/definitions/RunTimeSpec" + } + ] + } + }, + "required": [ + "size", + "run_time" + ], + "additionalProperties": false + }, + "LumpedPort": { + "title": "LumpedPort", + "description": "Class representing a single rectangular lumped port.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the port.\nimpedance : Union[tidycomplex, ComplexNumber] = 50\n [units = ohm]. Reference port impedance for scattering parameter computation.\nnum_grid_cells : Optional[PositiveInt] = 3\n Number of mesh grid cells associated with the port along each direction, which are added through automatic mesh refinement. A value of ``None`` will turn off automatic mesh refinement.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped port for more accurate modelling.\nvoltage_axis : Literal[0, 1, 2]\n Specifies the axis along which the E-field line integral is performed when computing the port voltage. The integration axis must lie in the plane of the port.\nsnap_perimeter_to_grid : bool = True\n When enabled, the perimeter of the port is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. A :class:`LumpedPort` is always snapped to the grid along its injection axis.\ndist_type : Literal['off', 'laterally_only', 'on'] = on\n Optional field that is passed directly to the :class:`.LinearLumpedElement` used to model the port's load. When set to ``on``, the network portion of the lumped port, including the source, is distributedacross the entirety of the lumped element's bounding box. When set to ``off``, the network portion of the lumped port is restricted to one cell and PEC connections are used to connect the network cell to the edges of the lumped element. A third option exists ``laterally_only``, where the network portion is only distributed along the lateral axis of the lumped port.\n\nExample\n-------\n>>> port1 = LumpedPort(center=(0, 0, 0),\n... size=(0, 1, 2),\n... voltage_axis=2,\n... name=\"port_1\",\n... impedance=50\n... ) # doctest: +SKIP\n\nSee Also\n--------\n:class:`.LinearLumpedElement`\n The lumped element representing the load of the port.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "LumpedPort", + "enum": [ + "LumpedPort" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the port.", + "minLength": 1, + "type": "string" + }, + "impedance": { + "title": "Reference impedance", + "description": "Reference port impedance for scattering parameter computation.", + "default": 50, + "units": "ohm", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "num_grid_cells": { + "title": "Port grid cells", + "description": "Number of mesh grid cells associated with the port along each direction, which are added through automatic mesh refinement. A value of ``None`` will turn off automatic mesh refinement.", + "default": 3, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Port", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped port for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "voltage_axis": { + "title": "Voltage Integration Axis", + "description": "Specifies the axis along which the E-field line integral is performed when computing the port voltage. The integration axis must lie in the plane of the port.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "snap_perimeter_to_grid": { + "title": "Snap Perimeter to Grid", + "description": "When enabled, the perimeter of the port is snapped to the simulation grid, which improves accuracy when the number of grid cells is low within the element. A :class:`LumpedPort` is always snapped to the grid along its injection axis.", + "default": true, + "type": "boolean" + }, + "dist_type": { + "title": "Distribute Type", + "description": "Optional field that is passed directly to the :class:`.LinearLumpedElement` used to model the port's load. When set to ``on``, the network portion of the lumped port, including the source, is distributedacross the entirety of the lumped element's bounding box. When set to ``off``, the network portion of the lumped port is restricted to one cell and PEC connections are used to connect the network cell to the edges of the lumped element. A third option exists ``laterally_only``, where the network portion is only distributed along the lateral axis of the lumped port.", + "default": "on", + "enum": [ + "off", + "laterally_only", + "on" + ], + "type": "string" + } + }, + "required": [ + "size", + "name", + "voltage_axis" + ], + "additionalProperties": false + }, + "CoaxialLumpedPort": { + "title": "CoaxialLumpedPort", + "description": "Class representing a single coaxial lumped port.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : ConstrainedStrValue\n Unique name for the port.\nimpedance : Union[tidycomplex, ComplexNumber] = 50\n [units = ohm]. Reference port impedance for scattering parameter computation.\nnum_grid_cells : Optional[PositiveInt] = 3\n Number of mesh grid cells associated with the port along each direction, which are added through automatic mesh refinement. A value of ``None`` will turn off automatic mesh refinement.\nenable_snapping_points : bool = True\n When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped port for more accurate modelling.\ncenter : Tuple[float, float, float] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nouter_diameter : PositiveFloat\n [units = um]. Diameter of the outer coaxial circle.\ninner_diameter : PositiveFloat\n [units = um]. Diameter of the inner coaxial circle.\nnormal_axis : Literal[0, 1, 2]\n Specifies the axis which is normal to the concentric circles.\ndirection : Literal['+', '-']\n The direction of the signal travelling in the transmission line. This is needed in order to position the path integral, which is used for computing conduction current using Amp\u00e8re's circuital law.\n\nExample\n-------\n>>> port1 = CoaxialLumpedPort(center=(0, 0, 0),\n... outer_diameter=4,\n... inner_diameter=1,\n... normal_axis=2,\n... direction=\"+\",\n... name=\"coax_port_1\",\n... impedance=50\n... ) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CoaxialLumpedPort", + "enum": [ + "CoaxialLumpedPort" + ], + "type": "string" + }, + "name": { + "title": "Name", + "description": "Unique name for the port.", + "minLength": 1, + "type": "string" + }, + "impedance": { + "title": "Reference impedance", + "description": "Reference port impedance for scattering parameter computation.", + "default": 50, + "units": "ohm", + "anyOf": [ + { + "title": "ComplexNumber", + "description": "Complex number with a well defined schema.", + "type": "object", + "properties": { + "real": { + "title": "Real", + "type": "number" + }, + "imag": { + "title": "Imag", + "type": "number" + } + }, + "required": [ + "real", + "imag" + ] + }, + { + "$ref": "#/definitions/ComplexNumber" + } + ] + }, + "num_grid_cells": { + "title": "Port grid cells", + "description": "Number of mesh grid cells associated with the port along each direction, which are added through automatic mesh refinement. A value of ``None`` will turn off automatic mesh refinement.", + "default": 3, + "exclusiveMinimum": 0, + "type": "integer" + }, + "enable_snapping_points": { + "title": "Snap Grid To Lumped Port", + "description": "When enabled, snapping points are automatically generated to snap grids to key geometric features of the lumped port for more accurate modelling.", + "default": true, + "type": "boolean" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "outer_diameter": { + "title": "Outer Diameter", + "description": "Diameter of the outer coaxial circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "inner_diameter": { + "title": "Inner Diameter", + "description": "Diameter of the inner coaxial circle.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "normal_axis": { + "title": "Normal Axis", + "description": "Specifies the axis which is normal to the concentric circles.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "direction": { + "title": "Direction", + "description": "The direction of the signal travelling in the transmission line. This is needed in order to position the path integral, which is used for computing conduction current using Amp\u00e8re's circuital law.", + "enum": [ + "+", + "-" + ], + "type": "string" + } + }, + "required": [ + "name", + "outer_diameter", + "inner_diameter", + "normal_axis", + "direction" + ], + "additionalProperties": false + }, + "VoltageIntegralAxisAligned": { + "title": "VoltageIntegralAxisAligned", + "description": "Class for computing the voltage between two points defined by an axis-aligned line.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nextrapolate_to_endpoints : bool = False\n If the endpoints of the path integral terminate at or near a material interface, the field is likely discontinuous. When this field is ``True``, fields that are outside and on the bounds of the integral are ignored. Should be enabled when computing voltage between two conductors.\nsnap_path_to_grid : bool = False\n It might be desireable to integrate exactly along the Yee grid associated with a field. When this field is ``True``, the integration path will be snapped to the grid.\nsign : Literal['+', '-']\n Positive indicates V=Vb-Va where position b has a larger coordinate along the axis of integration.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VoltageIntegralAxisAligned", + "enum": [ + "VoltageIntegralAxisAligned" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "extrapolate_to_endpoints": { + "title": "Extrapolate to Endpoints", + "description": "If the endpoints of the path integral terminate at or near a material interface, the field is likely discontinuous. When this field is ``True``, fields that are outside and on the bounds of the integral are ignored. Should be enabled when computing voltage between two conductors.", + "default": false, + "type": "boolean" + }, + "snap_path_to_grid": { + "title": "Snap Path to Grid", + "description": "It might be desireable to integrate exactly along the Yee grid associated with a field. When this field is ``True``, the integration path will be snapped to the grid.", + "default": false, + "type": "boolean" + }, + "sign": { + "title": "Direction of Path Integral", + "description": "Positive indicates V=Vb-Va where position b has a larger coordinate along the axis of integration.", + "enum": [ + "+", + "-" + ], + "type": "string" + } + }, + "required": [ + "size", + "sign" + ], + "additionalProperties": false + }, + "CustomVoltageIntegral2D": { + "title": "CustomVoltageIntegral2D", + "description": "Class for computing the voltage between two points defined by a custom path.\nComputed voltage is :math:`V=V_b-V_a`, where position b is the final vertex in the supplied path.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nposition : float\n Position of the plane along the ``axis``.\nvertices : ArrayLike[dtype=float, ndim=2]\n [units = um]. List of (d1, d2) defining the 2 dimensional positions of the path. The index of dimension should be in the ascending order, which means if the axis corresponds with ``y``, the coordinates of the vertices should be (x, z). If you wish to indicate a closed contour, the final vertex should be made equal to the first vertex, i.e., ``vertices[-1] == vertices[0]``\n\nNotes\n-----\n\nUse :class:`.VoltageIntegralAxisAligned` if possible, since interpolation\nnear conductors will not be accurate.\n\n.. TODO Improve by including extrapolate_to_endpoints field, non-trivial extension.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomVoltageIntegral2D", + "enum": [ + "CustomVoltageIntegral2D" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "position": { + "title": "Position", + "description": "Position of the plane along the ``axis``.", + "type": "number" + }, + "vertices": { + "title": "Vertices", + "description": "List of (d1, d2) defining the 2 dimensional positions of the path. The index of dimension should be in the ascending order, which means if the axis corresponds with ``y``, the coordinates of the vertices should be (x, z). If you wish to indicate a closed contour, the final vertex should be made equal to the first vertex, i.e., ``vertices[-1] == vertices[0]``", + "units": "um", + "type": "ArrayLike" + } + }, + "required": [ + "position", + "vertices" + ], + "additionalProperties": false + }, + "CurrentIntegralAxisAligned": { + "title": "CurrentIntegralAxisAligned", + "description": "Class for computing conduction current via Amp\u00e8re's circuital law on an axis-aligned loop.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nsign : Literal['+', '-']\n Positive indicates current flowing in the positive normal axis direction.\nextrapolate_to_endpoints : bool = False\n This parameter is passed to :class:`AxisAlignedPathIntegral` objects when computing the contour integral.\nsnap_contour_to_grid : bool = False\n This parameter is passed to :class:`AxisAlignedPathIntegral` objects when computing the contour integral.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CurrentIntegralAxisAligned", + "enum": [ + "CurrentIntegralAxisAligned" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "sign": { + "title": "Direction of Contour Integral", + "description": "Positive indicates current flowing in the positive normal axis direction.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "extrapolate_to_endpoints": { + "title": "Extrapolate to Endpoints", + "description": "This parameter is passed to :class:`AxisAlignedPathIntegral` objects when computing the contour integral.", + "default": false, + "type": "boolean" + }, + "snap_contour_to_grid": { + "title": "Snap Contour to Grid", + "description": "This parameter is passed to :class:`AxisAlignedPathIntegral` objects when computing the contour integral.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "sign" + ], + "additionalProperties": false + }, + "CustomCurrentIntegral2D": { + "title": "CustomCurrentIntegral2D", + "description": "Class for computing conduction current via Amp\u00e8re's circuital law on a custom path.\nTo compute the current flowing in the positive ``axis`` direction, the vertices should be\nordered in a counterclockwise direction.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\naxis : Literal[0, 1, 2] = 2\n Specifies dimension of the planar axis (0,1,2) -> (x,y,z).\nposition : float\n Position of the plane along the ``axis``.\nvertices : ArrayLike[dtype=float, ndim=2]\n [units = um]. List of (d1, d2) defining the 2 dimensional positions of the path. The index of dimension should be in the ascending order, which means if the axis corresponds with ``y``, the coordinates of the vertices should be (x, z). If you wish to indicate a closed contour, the final vertex should be made equal to the first vertex, i.e., ``vertices[-1] == vertices[0]``", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CustomCurrentIntegral2D", + "enum": [ + "CustomCurrentIntegral2D" + ], + "type": "string" + }, + "axis": { + "title": "Axis", + "description": "Specifies dimension of the planar axis (0,1,2) -> (x,y,z).", + "default": 2, + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "position": { + "title": "Position", + "description": "Position of the plane along the ``axis``.", + "type": "number" + }, + "vertices": { + "title": "Vertices", + "description": "List of (d1, d2) defining the 2 dimensional positions of the path. The index of dimension should be in the ascending order, which means if the axis corresponds with ``y``, the coordinates of the vertices should be (x, z). If you wish to indicate a closed contour, the final vertex should be made equal to the first vertex, i.e., ``vertices[-1] == vertices[0]``", + "units": "um", + "type": "ArrayLike" + } + }, + "required": [ + "position", + "vertices" + ], + "additionalProperties": false + }, + "WavePort": { + "title": "WavePort", + "description": "Class representing a single wave port\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for the port.\ndirection : Literal['+', '-']\n '+' or '-', defining which direction is considered 'input'.\nmode_spec : ModeSpec = ModeSpec(attrs={}, num_modes=1, target_neff=None, num_pml=(0,, 0), filter_pol=None, angle_theta=0.0, angle_phi=0.0, precision='double', bend_radius=None, bend_axis=None, angle_rotation=False, track_freq='central', group_index_step=False, type='ModeSpec')\n Parameters to feed to mode solver which determine modes measured by monitor.\nmode_index : NonNegativeInt = 0\n Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.\nvoltage_integral : Union[VoltageIntegralAxisAligned, CustomVoltageIntegral2D, NoneType] = None\n Definition of voltage integral used to compute voltage and the characteristic impedance.\ncurrent_integral : Union[CurrentIntegralAxisAligned, CustomCurrentIntegral2D, NoneType] = None\n Definition of current integral used to compute current and the characteristic impedance.\nnum_grid_cells : Optional[ConstrainedIntValue] = 5\n Number of mesh grid cells in the transverse plane of the `WavePort`. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. Must be greater than or equal to 3. When set to `None`, no grid refinement is performed.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "WavePort", + "enum": [ + "WavePort" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for the port.", + "minLength": 1, + "type": "string" + }, + "direction": { + "title": "Direction", + "description": "'+' or '-', defining which direction is considered 'input'.", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Parameters to feed to mode solver which determine modes measured by monitor.", + "default": { + "attrs": {}, + "num_modes": 1, + "target_neff": null, + "num_pml": [ + 0, + 0 + ], + "filter_pol": null, + "angle_theta": 0.0, + "angle_phi": 0.0, + "precision": "double", + "bend_radius": null, + "bend_axis": null, + "angle_rotation": false, + "track_freq": "central", + "group_index_step": false, + "type": "ModeSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "mode_index": { + "title": "Mode Index", + "description": "Index into the collection of modes returned by mode solver. Specifies which mode to inject using this source. If larger than ``mode_spec.num_modes``, ``num_modes`` in the solver will be set to ``mode_index + 1``.", + "default": 0, + "minimum": 0, + "type": "integer" + }, + "voltage_integral": { + "title": "Voltage Integral", + "description": "Definition of voltage integral used to compute voltage and the characteristic impedance.", + "anyOf": [ + { + "$ref": "#/definitions/VoltageIntegralAxisAligned" + }, + { + "$ref": "#/definitions/CustomVoltageIntegral2D" + } + ] + }, + "current_integral": { + "title": "Current Integral", + "description": "Definition of current integral used to compute current and the characteristic impedance.", + "anyOf": [ + { + "$ref": "#/definitions/CurrentIntegralAxisAligned" + }, + { + "$ref": "#/definitions/CustomCurrentIntegral2D" + } + ] + }, + "num_grid_cells": { + "title": "Number of Grid Cells", + "description": "Number of mesh grid cells in the transverse plane of the `WavePort`. Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. Must be greater than or equal to 3. When set to `None`, no grid refinement is performed.", + "default": 5, + "minimum": 3, + "type": "integer" + } + }, + "required": [ + "size", + "name", + "direction" + ], + "additionalProperties": false + }, + "HeatSource": { + "title": "HeatSource", + "description": "Adds a volumetric heat source (heat sink if negative values\nare provided) to specific structures in the scene.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = HeatSource(rate=1, structures=[\"box\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatSource", + "enum": [ + "HeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "HeatFromElectricSource": { + "title": "HeatFromElectricSource", + "description": "Volumetric heat source generated from an electric simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\n\nNotes\n-----\n\n If a :class`HeatFromElectricSource` is specified as a source, appropriate boundary\n conditions for an electric simulation must be provided, since such a simulation\n will be executed before the heat simulation can run.\n\nExample\n-------\n>>> heat_source = HeatFromElectricSource()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "HeatFromElectricSource", + "enum": [ + "HeatFromElectricSource" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UniformHeatSource": { + "title": "UniformHeatSource", + "description": "Volumetric heat source. This class is deprecated. You can use\n'HeatSource' instead.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n Optional name for the source.\nstructures : Tuple[str, ...]\n Names of structures where to apply heat source.\nrate : Union[float, SpatialDataArray]\n [units = W/um^3]. Volumetric rate of heating or cooling (if negative) in units of W/um^3.\n\nExample\n-------\n>>> heat_source = UniformHeatSource(rate=1, structures=[\"box\"]) # doctest: +SKIP", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "description": "Optional name for the source.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "UniformHeatSource", + "enum": [ + "UniformHeatSource" + ], + "type": "string" + }, + "structures": { + "title": "Target Structures", + "description": "Names of structures where to apply heat source.", + "type": "array", + "items": { + "type": "string" + } + }, + "rate": { + "title": "Volumetric Heat Rate", + "description": "Volumetric rate of heating or cooling (if negative) in units of W/um^3.", + "units": "W/um^3", + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + } + }, + "required": [ + "structures", + "rate" + ], + "additionalProperties": false + }, + "StructureBoundary": { + "title": "StructureBoundary", + "description": "Placement of boundary conditions on the structure's boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\n\nExample\n-------\n>>> bc_placement = StructureBoundary(structure=\"box\")", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureBoundary", + "enum": [ + "StructureBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "StructureStructureInterface": { + "title": "StructureStructureInterface", + "description": "Placement of boundary conditions between two structures.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructures : Tuple[str, str]\n Names of two structures.\n\nExample\n-------\n>>> bc_placement = StructureStructureInterface(structures=[\"box\", \"sphere\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureStructureInterface", + "enum": [ + "StructureStructureInterface" + ], + "type": "string" + }, + "structures": { + "title": "Structures", + "description": "Names of two structures.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "structures" + ], + "additionalProperties": false + }, + "MediumMediumInterface": { + "title": "MediumMediumInterface", + "description": "Placement of boundary conditions between two mediums.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nmediums : Tuple[str, str]\n Names of two mediums.\n\nExample\n-------\n>>> bc_placement = MediumMediumInterface(mediums=[\"dieletric\", \"metal\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "MediumMediumInterface", + "enum": [ + "MediumMediumInterface" + ], + "type": "string" + }, + "mediums": { + "title": "Mediums", + "description": "Names of two mediums.", + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string" + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "mediums" + ], + "additionalProperties": false + }, + "SimulationBoundary": { + "title": "SimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = SimulationBoundary(surfaces=[\"x-\", \"x+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SimulationBoundary", + "enum": [ + "SimulationBoundary" + ], + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "additionalProperties": false + }, + "StructureSimulationBoundary": { + "title": "StructureSimulationBoundary", + "description": "Placement of boundary conditions on the simulation box boundary covered by the structure.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nstructure : str\n Name of the structure.\nsurfaces : Tuple[Literal['x-', 'x+', 'y-', 'y+', 'z-', 'z+'], ...] = ('x-', 'x+', 'y-', 'y+', 'z-', 'z+')\n Surfaces of simulation domain where to apply boundary conditions.\n\nExample\n-------\n>>> bc_placement = StructureSimulationBoundary(structure=\"box\", surfaces=[\"y-\", \"y+\"])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "StructureSimulationBoundary", + "enum": [ + "StructureSimulationBoundary" + ], + "type": "string" + }, + "structure": { + "title": "Structure Name", + "description": "Name of the structure.", + "type": "string" + }, + "surfaces": { + "title": "Surfaces", + "description": "Surfaces of simulation domain where to apply boundary conditions.", + "default": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "array", + "items": { + "enum": [ + "x-", + "x+", + "y-", + "y+", + "z-", + "z+" + ], + "type": "string" + } + } + }, + "required": [ + "structure" + ], + "additionalProperties": false + }, + "TemperatureBC": { + "title": "TemperatureBC", + "description": "Constant temperature thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat\n [units = K]. Temperature value in units of K.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.TemperatureBC(temperature=300)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureBC", + "enum": [ + "TemperatureBC" + ], + "type": "string" + }, + "temperature": { + "title": "Temperature", + "description": "Temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + } + }, + "required": [ + "temperature" + ], + "additionalProperties": false + }, + "HeatFluxBC": { + "title": "HeatFluxBC", + "description": "Constant flux thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nflux : float\n [units = W/um^2]. Heat flux value in units of W/um^2.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.HeatFluxBC(flux=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatFluxBC", + "enum": [ + "HeatFluxBC" + ], + "type": "string" + }, + "flux": { + "title": "Heat Flux", + "description": "Heat flux value in units of W/um^2.", + "units": "W/um^2", + "type": "number" + } + }, + "required": [ + "flux" + ], + "additionalProperties": false + }, + "ConvectionBC": { + "title": "ConvectionBC", + "description": "Convective thermal boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nambient_temperature : PositiveFloat\n [units = K]. Ambient temperature value in units of K.\ntransfer_coeff : NonNegativeFloat\n [units = W/(um^2*K)]. Heat flux value in units of W/(um^2*K).\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc = td.ConvectionBC(ambient_temperature=300, transfer_coeff=1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ConvectionBC", + "enum": [ + "ConvectionBC" + ], + "type": "string" + }, + "ambient_temperature": { + "title": "Ambient Temperature", + "description": "Ambient temperature value in units of K.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "transfer_coeff": { + "title": "Heat Transfer Coefficient", + "description": "Heat flux value in units of W/(um^2*K).", + "units": "W/(um^2*K)", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "ambient_temperature", + "transfer_coeff" + ], + "additionalProperties": false + }, + "DCVoltageSource": { + "title": "DCVoltageSource", + "description": "DC voltage source in volts.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n voltage : ArrayLike[dtype=float, ndim=1]\n [units = V]. DC voltage usually used as source in 'VoltageBC' boundary conditions.\nunits : Literal['V'] = V\n \nNotes\n-----\n\n This voltage refers to potential above the equivalent simulation ground. Currently, electrical ports\n are not defined.\n\nExamples\n--------\n>>> import tidy3d as td\n>>> voltages = [-0.5, 0, 1, 2, 3, 4]\n>>> voltage_source = td.DCVoltageSource(voltage=voltages)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "voltage": { + "title": "Voltage", + "description": "DC voltage usually used as source in 'VoltageBC' boundary conditions.", + "units": "V", + "type": "ArrayLike" + }, + "units": { + "title": "Units", + "default": "V", + "enum": [ + "V" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCVoltageSource", + "enum": [ + "DCVoltageSource" + ], + "type": "string" + } + }, + "required": [ + "voltage" + ], + "additionalProperties": false + }, + "VoltageBC": { + "title": "VoltageBC", + "description": "Constant electric potential (voltage) :math:`= \\text{V}` boundary condition.\nSets a potential at the specified boundary.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCVoltageSource\n [units = V]. Electric potential to be applied at the specified boundary.\n\nNotes\n-----\n\n In charge simulations it also accepts an array of voltages.\n In this case, a solution for each of these voltages will\n be computed.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_source = td.DCVoltageSource(voltage=1)\n>>> voltage_bc = td.VoltageBC(source=voltage_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VoltageBC", + "enum": [ + "VoltageBC" + ], + "type": "string" + }, + "source": { + "title": "Voltage", + "description": "Electric potential to be applied at the specified boundary.", + "units": "V", + "allOf": [ + { + "$ref": "#/definitions/DCVoltageSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "DCCurrentSource": { + "title": "DCCurrentSource", + "description": "DC current source in amperes.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nname : Optional[str] = None\n current : FiniteFloat\n [units = A]. DC current usually used as source in 'CurrentBC' boundary conditions.\nunits : Literal['A'] = A\n \nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=0.4)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "name": { + "title": "Name", + "type": "string" + }, + "current": { + "title": "Current", + "description": "DC current usually used as source in 'CurrentBC' boundary conditions.", + "units": "A", + "type": "number" + }, + "units": { + "title": "Units", + "default": "A", + "enum": [ + "A" + ], + "type": "string" + }, + "type": { + "title": "Type", + "default": "DCCurrentSource", + "enum": [ + "DCCurrentSource" + ], + "type": "string" + } + }, + "required": [ + "current" + ], + "additionalProperties": false + }, + "CurrentBC": { + "title": "CurrentBC", + "description": "Current boundary conditions.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsource : DCCurrentSource\n [units = A/um^2]. A current source\n\nExample\n-------\n>>> import tidy3d as td\n>>> current_source = td.DCCurrentSource(current=1)\n>>> current_bc = CurrentBC(source=current_source)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "CurrentBC", + "enum": [ + "CurrentBC" + ], + "type": "string" + }, + "source": { + "title": "Current Source", + "description": "A current source", + "units": "A/um^2", + "allOf": [ + { + "$ref": "#/definitions/DCCurrentSource" + } + ] + } + }, + "required": [ + "source" + ], + "additionalProperties": false + }, + "InsulatingBC": { + "title": "InsulatingBC", + "description": "Insulation boundary condition.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\n\nNotes\n-----\n\n Ensures the electric potential to the normal :math:`\\nabla \\psi \\cdot \\mathbf{n} = 0` as well as the\n surface recombination current density :math:`J_s = \\mathbf{J} \\cdot \\mathbf{n} = 0` are set to zero where\n the current density is :math:`\\mathbf{J_n}` and the normal vector is :math:`\\mathbf{n}`\n\nExample\n-------\n>>> bc = InsulatingBC()", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "InsulatingBC", + "enum": [ + "InsulatingBC" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "HeatChargeBoundarySpec": { + "title": "HeatChargeBoundarySpec", + "description": "Heat-Charge boundary conditions specification.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nExample\n-------\n>>> import tidy3d as td\n>>> bc_v1 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),\n... placement=td.StructureBoundary(structure=\"contact_left\"),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatChargeBoundarySpec", + "enum": [ + "HeatChargeBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "HeatBoundarySpec": { + "title": "HeatBoundarySpec", + "description": "Heat BC specification. DEPRECIATED.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nplacement : Union[StructureBoundary, StructureStructureInterface, MediumMediumInterface, SimulationBoundary, StructureSimulationBoundary]\n Location to apply boundary conditions.\ncondition : Union[TemperatureBC, HeatFluxBC, ConvectionBC, VoltageBC, CurrentBC, InsulatingBC]\n Boundary conditions to apply at the selected location.\n\nWarning\n-------\n Included backward-compatibility only.\n\nExample\n--------\n>>> import tidy3d as td\n>>> bc_spec = td.HeatBoundarySpec(\n... placement=td.SimulationBoundary(),\n... condition=td.ConvectionBC(ambient_temperature=300, transfer_coeff=1),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "placement": { + "title": "Boundary Conditions Placement", + "description": "Location to apply boundary conditions.", + "discriminator": { + "propertyName": "type", + "mapping": { + "StructureBoundary": "#/definitions/StructureBoundary", + "StructureStructureInterface": "#/definitions/StructureStructureInterface", + "MediumMediumInterface": "#/definitions/MediumMediumInterface", + "SimulationBoundary": "#/definitions/SimulationBoundary", + "StructureSimulationBoundary": "#/definitions/StructureSimulationBoundary" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/StructureBoundary" + }, + { + "$ref": "#/definitions/StructureStructureInterface" + }, + { + "$ref": "#/definitions/MediumMediumInterface" + }, + { + "$ref": "#/definitions/SimulationBoundary" + }, + { + "$ref": "#/definitions/StructureSimulationBoundary" + } + ] + }, + "condition": { + "title": "Boundary Conditions", + "description": "Boundary conditions to apply at the selected location.", + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureBC": "#/definitions/TemperatureBC", + "HeatFluxBC": "#/definitions/HeatFluxBC", + "ConvectionBC": "#/definitions/ConvectionBC", + "VoltageBC": "#/definitions/VoltageBC", + "CurrentBC": "#/definitions/CurrentBC", + "InsulatingBC": "#/definitions/InsulatingBC" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureBC" + }, + { + "$ref": "#/definitions/HeatFluxBC" + }, + { + "$ref": "#/definitions/ConvectionBC" + }, + { + "$ref": "#/definitions/VoltageBC" + }, + { + "$ref": "#/definitions/CurrentBC" + }, + { + "$ref": "#/definitions/InsulatingBC" + } + ] + }, + "type": { + "title": "Type", + "default": "HeatBoundarySpec", + "enum": [ + "HeatBoundarySpec" + ], + "type": "string" + } + }, + "required": [ + "placement", + "condition" + ], + "additionalProperties": false + }, + "TemperatureMonitor": { + "title": "TemperatureMonitor", + "description": "Temperature monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\ninterval : PositiveInt = 1\n Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "TemperatureMonitor", + "enum": [ + "TemperatureMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + }, + "interval": { + "title": "Interval", + "description": "Sampling rate of the monitor: number of time steps between each measurement. Set ``interval`` to 1 for the highest possible resolution in time. Higher integer values down-sample the data by measuring every ``interval`` time steps. This can be useful for reducing data storage as needed by the application.NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyPotentialMonitor": { + "title": "SteadyPotentialMonitor", + "description": "Electric potential (:math:`\\psi`) monitor.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : bool = False\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyPotentialMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyPotentialMonitor", + "enum": [ + "SteadyPotentialMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": false, + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyFreeCarrierMonitor": { + "title": "SteadyFreeCarrierMonitor", + "description": "Free-carrier monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> voltage_monitor_z0 = td.SteadyFreeCarrierMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"voltage_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyFreeCarrierMonitor", + "enum": [ + "SteadyFreeCarrierMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyEnergyBandMonitor": { + "title": "SteadyEnergyBandMonitor", + "description": "Energy bands monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> energy_monitor_z0 = td.SteadyEnergyBandMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"bands_z0\", unstructured=True,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyEnergyBandMonitor", + "enum": [ + "SteadyEnergyBandMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyElectricFieldMonitor": { + "title": "SteadyElectricFieldMonitor", + "description": "Electric field monitor for Charge simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> electric_field_monitor_z0 = td.SteadyElectricFieldMonitor(\n... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name=\"electric_field_z0\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyElectricFieldMonitor", + "enum": [ + "SteadyElectricFieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "SteadyCapacitanceMonitor": { + "title": "SteadyCapacitanceMonitor", + "description": "Capacitance monitor associated with a charge simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return data on the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.\n\nExample\n-------\n>>> import tidy3d as td\n>>> capacitance_global_mnt = td.SteadyCapacitanceMonitor(\n... center=(0, 0.14, 0), size=(td.inf, td.inf, 0), name=\"capacitance_global_mnt\",\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "SteadyCapacitanceMonitor", + "enum": [ + "SteadyCapacitanceMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return data on the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "UniformUnstructuredGrid": { + "title": "UniformUnstructuredGrid", + "description": "Uniform grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl : PositiveFloat\n [units = um]. Grid size for uniform grid generation.\nmin_edges_per_circumference : PositiveFloat = 15\n Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.\nmin_edges_per_side : PositiveFloat = 2\n Enforced minimum number of mesh segments per any side of an object.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.\n\nExample\n-------\n>>> heat_grid = UniformUnstructuredGrid(dl=0.1)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "UniformUnstructuredGrid", + "enum": [ + "UniformUnstructuredGrid" + ], + "type": "string" + }, + "dl": { + "title": "Grid Size", + "description": "Grid size for uniform grid generation.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_circumference": { + "title": "Minimum Edges per Circumference", + "description": "Enforced minimum number of mesh segments per circumference of an object. Applies to :class:`Cylinder` and :class:`Sphere`, for which the circumference is taken as 2 * pi * radius.", + "default": 15, + "exclusiveMinimum": 0, + "type": "number" + }, + "min_edges_per_side": { + "title": "Minimum Edges per Side", + "description": "Enforced minimum number of mesh segments per any side of an object.", + "default": 2, + "exclusiveMinimum": 0, + "type": "number" + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``min_edges_per_circumference`` and ``min_edges_per_side`` will not be enforced. The original ``dl`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "dl" + ], + "additionalProperties": false + }, + "GridRefinementRegion": { + "title": "GridRefinementRegion", + "description": "Refinement region for the unstructured mesh. The cell size is enforced to be constant inside the region.\nThe cell size outside of the region depends on the distance from the region.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\ndl_internal : PositiveFloat\n [units = um]. Mesh cell size inside the refinement region\ntransition_thickness : NonNegativeFloat\n [units = um]. Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "GridRefinementRegion", + "enum": [ + "GridRefinementRegion" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "dl_internal": { + "title": "Internal mesh cell size", + "description": "Mesh cell size inside the refinement region", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "transition_thickness": { + "title": "Interface Distance", + "description": "Thickness of a transition layer outside the box where the mesh cell size changes from theinternal size to the external one.", + "units": "um", + "minimum": 0, + "type": "number" + } + }, + "required": [ + "size", + "dl_internal", + "transition_thickness" + ], + "additionalProperties": false + }, + "GridRefinementLine": { + "title": "GridRefinementLine", + "description": "Refinement line for the unstructured mesh. The cell size depends on the distance from the line.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nr1 : Tuple[float, float, float]\n [units = um]. Start point of the line in x, y, and z.\nr2 : Tuple[float, float, float]\n [units = um]. End point of the line in x, y, and z.\ndl_near : PositiveFloat\n [units = um]. Mesh cell size near the line\ndistance_near : NonNegativeFloat\n [units = um]. Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "r1": { + "title": "Start point of the line", + "description": "Start point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "r2": { + "title": "End point of the line", + "description": "End point of the line in x, y, and z.", + "units": "um", + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "number" + }, + { + "type": "number" + }, + { + "type": "number" + } + ] + }, + "dl_near": { + "title": "Mesh cell size near the line", + "description": "Mesh cell size near the line", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_near": { + "title": "Near distance", + "description": "Distance from the line within which ``dl_near`` is enforced.Typically the same as ``dl_near`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk distance", + "description": "Distance from the line outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_near`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "GridRefinementLine", + "enum": [ + "GridRefinementLine" + ], + "type": "string" + } + }, + "required": [ + "r1", + "r2", + "dl_near", + "distance_near", + "distance_bulk" + ], + "additionalProperties": false + }, + "DistanceUnstructuredGrid": { + "title": "DistanceUnstructuredGrid", + "description": "Adaptive grid based on distance to material interfaces. Currently not recommended for larger\nsimulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nrelative_min_dl : NonNegativeFloat = 0.001\n The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.\ndl_interface : PositiveFloat\n [units = um]. Grid size near material interfaces.\ndl_bulk : PositiveFloat\n [units = um]. Grid size away from material interfaces.\ndistance_interface : NonNegativeFloat\n [units = um]. Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.\ndistance_bulk : NonNegativeFloat\n [units = um]. Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.\nsampling : PositiveFloat = 100\n An internal advanced parameter that defines number of sampling points per surface when computing distance values.\nuniform_grid_mediums : Tuple[str, ...] = ()\n List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.\nnon_refined_structures : Tuple[str, ...] = ()\n List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.\nmesh_refinements : Tuple[Annotated[Union[tidy3d.components.tcad.grid.GridRefinementRegion, tidy3d.components.tcad.grid.GridRefinementLine], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of regions/lines for which the mesh refinement will be applied\n\nExample\n-------\n>>> heat_grid = DistanceUnstructuredGrid(\n... dl_interface=0.1,\n... dl_bulk=1,\n... distance_interface=0.3,\n... distance_bulk=2,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "relative_min_dl": { + "title": "Relative Mesh Size Limit", + "description": "The minimal allowed mesh size relative to the largest dimension of the simulation domain.Use ``relative_min_dl=0`` to remove this constraint.", + "default": 0.001, + "minimum": 0, + "type": "number" + }, + "type": { + "title": "Type", + "default": "DistanceUnstructuredGrid", + "enum": [ + "DistanceUnstructuredGrid" + ], + "type": "string" + }, + "dl_interface": { + "title": "Interface Grid Size", + "description": "Grid size near material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "dl_bulk": { + "title": "Bulk Grid Size", + "description": "Grid size away from material interfaces.", + "units": "um", + "exclusiveMinimum": 0, + "type": "number" + }, + "distance_interface": { + "title": "Interface Distance", + "description": "Distance from interface within which ``dl_interface`` is enforced.Typically the same as ``dl_interface`` or its multiple.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "distance_bulk": { + "title": "Bulk Distance", + "description": "Distance from interface outside of which ``dl_bulk`` is enforced.Typically twice of ``dl_bulk`` or its multiple. Use larger values for a smoother transition from ``dl_interface`` to ``dl_bulk``.", + "units": "um", + "minimum": 0, + "type": "number" + }, + "sampling": { + "title": "Surface Sampling", + "description": "An internal advanced parameter that defines number of sampling points per surface when computing distance values.", + "default": 100, + "exclusiveMinimum": 0, + "type": "number" + }, + "uniform_grid_mediums": { + "title": "Mediums With Uniform Refinement", + "description": "List of mediums for which ``dl_interface`` will be enforced everywhere in the volume.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "non_refined_structures": { + "title": "Structures Without Refinement", + "description": "List of structures for which ``dl_interface`` will not be enforced. ``dl_bulk`` is used instead.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "mesh_refinements": { + "title": "Mesh refinement structures", + "description": "List of regions/lines for which the mesh refinement will be applied", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "GridRefinementRegion": "#/definitions/GridRefinementRegion", + "GridRefinementLine": "#/definitions/GridRefinementLine" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GridRefinementRegion" + }, + { + "$ref": "#/definitions/GridRefinementLine" + } + ] + } + } + }, + "required": [ + "dl_interface", + "dl_bulk", + "distance_interface", + "distance_bulk" + ], + "additionalProperties": false + }, + "ChargeToleranceSpec": { + "title": "ChargeToleranceSpec", + "description": "Charge tolerance parameters relevant to multiple simulation analysis types.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nabs_tol : PositiveFloat = 10000000000.0\n Absolute tolerance used as stop criteria when converging towards a solution.\nrel_tol : PositiveFloat = 1e-10\n Relative tolerance used as stop criteria when converging towards a solution.\nmax_iters : PositiveInt = 30\n Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.\nramp_up_iters : PositiveInt = 1\n In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.\n\nExample\n-------\n>>> import tidy3d as td\n>>> charge_settings = td.ChargeToleranceSpec(abs_tol=1e8, rel_tol=1e-10, max_iters=30)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "abs_tol": { + "title": "Absolute tolerance.", + "description": "Absolute tolerance used as stop criteria when converging towards a solution.", + "default": 10000000000.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "rel_tol": { + "title": "Relative tolerance.", + "description": "Relative tolerance used as stop criteria when converging towards a solution.", + "default": 1e-10, + "exclusiveMinimum": 0, + "type": "number" + }, + "max_iters": { + "title": "Maximum number of iterations.", + "description": "Indicates the maximum number of iterations to be run. The solver will stop either when this maximum of iterations is met or when the tolerance criteria has been met.", + "default": 30, + "exclusiveMinimum": 0, + "type": "integer" + }, + "ramp_up_iters": { + "title": "Ramp-up iterations.", + "description": "In order to help in start up, quantities such as doping are ramped up until they reach their specified value. This parameter determines how many of this iterations it takes to reach full values.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "ChargeToleranceSpec", + "enum": [ + "ChargeToleranceSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "IsothermalSteadyChargeDCAnalysis": { + "title": "IsothermalSteadyChargeDCAnalysis", + "description": "Configures relevant steady-state DC simulation parameters for a charge simulation.\n\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntemperature : PositiveFloat = 300\n [units = K]. Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.\ntolerance_settings : ChargeToleranceSpec = ChargeToleranceSpec(attrs={}, abs_tol=10000000000.0, rel_tol=1e-10, max_iters=30, ramp_up_iters=1, type='ChargeToleranceSpec')\n convergence_dv : PositiveFloat = 1.0\n By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.\nfermi_dirac : bool = False\n Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "temperature": { + "title": "Temperature", + "description": "Lattice temperature. Assumed constant throughout the device. Carriers are assumed to be at thermodynamic equilibrium with the lattice.", + "default": 300, + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "tolerance_settings": { + "title": "Tolerance settings", + "default": { + "attrs": {}, + "abs_tol": 10000000000.0, + "rel_tol": 1e-10, + "max_iters": 30, + "ramp_up_iters": 1, + "type": "ChargeToleranceSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/ChargeToleranceSpec" + } + ] + }, + "convergence_dv": { + "title": "Bias step.", + "description": "By default, a solution is computed at 0 bias. If a bias different than 0 is requested through a voltage source, the charge solver will start at 0 and increase bias at `convergence_dv` intervals until the required bias is reached. This is, therefore, a convergence parameter in DC computations.", + "default": 1.0, + "exclusiveMinimum": 0, + "type": "number" + }, + "fermi_dirac": { + "title": "Fermi-Dirac statistics", + "description": "Determines whether Fermi-Dirac statistics are used. When False, Boltzmann statistics will be used. This can provide more accurate results in situations where very high doping may lead the pseudo-Fermi energy level to approach either the conduction or valence energy bands.", + "default": false, + "type": "boolean" + }, + "type": { + "title": "Type", + "default": "IsothermalSteadyChargeDCAnalysis", + "enum": [ + "IsothermalSteadyChargeDCAnalysis" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "UnsteadySpec": { + "title": "UnsteadySpec", + "description": "Defines an unsteady specification\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ntime_step : PositiveFloat\n [units = sec]. Time step taken for each iteration of the time integration loop.\ntotal_time_steps : PositiveInt\n Specifies the total number of time steps run during the simulation.\n\nExample\n--------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "time_step": { + "title": "Time-step", + "description": "Time step taken for each iteration of the time integration loop.", + "units": "sec", + "exclusiveMinimum": 0, + "type": "number" + }, + "total_time_steps": { + "title": "Total time steps", + "description": "Specifies the total number of time steps run during the simulation.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "type": { + "title": "Type", + "default": "UnsteadySpec", + "enum": [ + "UnsteadySpec" + ], + "type": "string" + } + }, + "required": [ + "time_step", + "total_time_steps" + ], + "additionalProperties": false + }, + "UnsteadyHeatAnalysis": { + "title": "UnsteadyHeatAnalysis", + "description": "Configures relevant unsteady-state heat simulation parameters.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ninitial_temperature : PositiveFloat\n [units = K]. Initial value for the temperature field.\nunsteady_spec : UnsteadySpec\n Time step and total time steps for the unsteady simulation.\n\nExample\n-------\n>>> import tidy3d as td\n>>> time_spec = td.UnsteadyHeatAnalysis(\n... initial_temperature=300,\n... unsteady_spec=td.UnsteadySpec(\n... time_step=0.01,\n... total_time_steps=200,\n... ),\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "initial_temperature": { + "title": "Initial temperature.", + "description": "Initial value for the temperature field.", + "units": "K", + "exclusiveMinimum": 0, + "type": "number" + }, + "unsteady_spec": { + "title": "Unsteady specification", + "description": "Time step and total time steps for the unsteady simulation.", + "allOf": [ + { + "$ref": "#/definitions/UnsteadySpec" + } + ] + }, + "type": { + "title": "Type", + "default": "UnsteadyHeatAnalysis", + "enum": [ + "UnsteadyHeatAnalysis" + ], + "type": "string" + } + }, + "required": [ + "initial_temperature", + "unsteady_spec" + ], + "additionalProperties": false + }, + "HeatChargeSimulation": { + "title": "HeatChargeSimulation", + "description": "Defines thermoelectric simulations.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, 1], Literal[0, 1], Literal[0, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).\nsources : Tuple[Annotated[Union[tidy3d.components.tcad.source.heat.HeatSource, tidy3d.components.tcad.source.coupled.HeatFromElectricSource, tidy3d.components.tcad.source.heat.UniformHeatSource], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of heat and/or charge sources.\nboundary_spec : Tuple[Annotated[Union[tidy3d.components.tcad.boundary.specification.HeatChargeBoundarySpec, tidy3d.components.tcad.boundary.specification.HeatBoundarySpec], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of boundary condition specifications.\nmonitors : Tuple[Annotated[Union[tidy3d.components.tcad.monitors.heat.TemperatureMonitor, tidy3d.components.tcad.monitors.charge.SteadyPotentialMonitor, tidy3d.components.tcad.monitors.charge.SteadyFreeCarrierMonitor, tidy3d.components.tcad.monitors.charge.SteadyEnergyBandMonitor, tidy3d.components.tcad.monitors.charge.SteadyElectricFieldMonitor, tidy3d.components.tcad.monitors.charge.SteadyCapacitanceMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Monitors in the simulation.\ngrid_spec : Union[UniformUnstructuredGrid, DistanceUnstructuredGrid]\n Grid specification for heat-charge simulation.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nanalysis_spec : Union[IsothermalSteadyChargeDCAnalysis, UnsteadyHeatAnalysis] = None\n The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.\n\nNotes\n-----\n A ``HeatChargeSimulation`` supports different types of simulations. It solves the\n heat and conduction equations using the Finite-Volume (FV) method. This solver\n determines the required computation physics according to the simulation scene definition.\n This is implemented in this way due to the strong multi-physics coupling.\n\nThe ``HeatChargeSimulation`` can solve multiple physics and the intention is to enable close thermo-electrical coupling.\n\nCurrently, this solver supports steady-state heat conduction where :math:`q` is the heat flux, :math:`k`\nis the thermal conductivity, and :math:`T` is the temperature.\n\n .. math::\n\n -\\nabla \\cdot (-k \\nabla T) = q\n\nIt is also possible to run transient heat simulations by specifying ``analysis_spec=UnsteadyHeatAnalysis(...)``. This adds\nthe temporal terms to the above equations:\n\n .. math::\n\n \\frac{\\partial \\rho c_p T}{\\partial t} -\\nabla \\cdot (k \\nabla(T)) = q\n\nwhere :math:`\\rho` is the density and :math:`c_p` is the specific heat capacity of the medium.\n\n\nThe steady-state electrical ``Conduction`` equation depends on the electric conductivity (:math:`\\sigma`) of a\nmedium, and the electric field (:math:`\\mathbf{E} = -\\nabla(\\psi)`) derived from electrical potential (:math:`\\psi`).\nCurrently, in this type of simulation, no current sources or sinks are supported.\n\n .. math::\n\n \\text{div}(\\sigma \\cdot \\nabla(\\psi)) = 0\n\n\nFor further details on what equations are solved in ``Charge`` simulations, refer to the :class:`SemiconductorMedium`.\n\nLet's understand how the physics solving is determined:\n\n .. list-table::\n :widths: 25 75\n :header-rows: 1\n\n * - Simulation Type\n - Example Configuration Settings\n * - ``Heat``\n - The heat equation is solved with specified heat sources,\n boundary conditions, etc. Structures should incorporate materials\n with defined heat properties.\n * - ``Conduction``\n - The electrical conduction equation is solved with\n specified boundary conditions such as ``SteadyVoltageBC``, ``SteadyCurrentBC``, ...\n * - ``Charge``\n - Drift-diffusion equations are solved for structures containing\n a defined :class:`SemiconductorMedium`. Insulators with a\n :class:`ChargeInsulatorMedium` can also be included. For these, only the\n electric potential field is calculated.\n\nExamples\n--------\nTo run a thermal (``Heat`` |:fire:|) simulation with a solid conductive structure:\n\n>>> import tidy3d as td\n>>> heat_sim = td.HeatChargeSimulation(\n... size=(3.0, 3.0, 3.0),\n... structures=[\n... td.Structure(\n... geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=td.Medium(\n... permittivity=2.0,\n... heat_spec=td.SolidSpec(\n... conductivity=1,\n... capacity=1,\n... )\n... ),\n... name=\"box\",\n... ),\n... ],\n... medium=td.Medium(permittivity=3.0, heat_spec=td.FluidSpec()),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.1),\n... sources=[td.HeatSource(rate=1, structures=[\"box\"])],\n... boundary_spec=[\n... td.HeatChargeBoundarySpec(\n... placement=td.StructureBoundary(structure=\"box\"),\n... condition=td.TemperatureBC(temperature=500),\n... )\n... ],\n... monitors=[td.TemperatureMonitor(size=(1, 2, 3), name=\"sample\")],\n... )\n\nTo run a drift-diffusion (``Charge`` |:zap:|) system:\n\n>>> import tidy3d as td\n>>> air = td.FluidMedium(\n... name=\"air\"\n... )\n>>> intrinsic_Si = td.material_library['cSi'].variants['Si_MultiPhysics'].medium.charge\n>>> Si_n = intrinsic_Si.updated_copy(N_d=1e16, name=\"Si_n\")\n>>> Si_p = intrinsic_Si.updated_copy(N_a=1e16, name=\"Si_p\")\n>>> n_side = td.Structure(\n... geometry=td.Box(center=(-0.5, 0, 0), size=(1, 1, 1)),\n... medium=Si_n,\n... name=\"n_side\"\n... )\n>>> p_side = td.Structure(\n... geometry=td.Box(center=(0.5, 0, 0), size=(1, 1, 1)),\n... medium=Si_p,\n... name=\"p_side\"\n... )\n>>> bc_v1 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[-1, 0, 0.5])),\n... placement=td.MediumMediumInterface(mediums=[air.name, Si_n.name]),\n... )\n>>> bc_v2 = td.HeatChargeBoundarySpec(\n... condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)),\n... placement=td.MediumMediumInterface(mediums=[air.name, Si_p.name]),\n... )\n>>> charge_sim = td.HeatChargeSimulation(\n... structures=[n_side, p_side],\n... medium=td.Medium(heat_spec=td.FluidSpec(), name=\"air\"),\n... monitors=[td.SteadyFreeCarrierMonitor(\n... center=(0, 0, 0), size=(td.inf, td.inf, 0), name=\"charge_mnt\", unstructured=True\n... )],\n... center=(0, 0, 0),\n... size=(3, 3, 3),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.05),\n... boundary_spec=[bc_v1, bc_v2],\n... analysis_spec=td.IsothermalSteadyChargeDCAnalysis(\n... tolerance_settings=td.ChargeToleranceSpec(rel_tol=1e5, abs_tol=3e3, max_iters=400),\n... convergence_dv=10),\n... )\n\n\nCoupling between ``Heat`` and electrical ``Conduction`` simulations is currently limited to 1-way.\nThis is specified by defining a heat source of type :class:`HeatFromElectricSource`. With this coupling, joule heating is\ncalculated as part of the solution to a ``Conduction`` simulation and translated into the ``Heat`` simulation.\n\nTwo common scenarios can use this coupling definition:\n 1. One in which BCs and sources are specified for both ``Heat`` and ``Conduction`` simulations.\n In this case one mesh will be generated and used for both the ``Conduction`` and ``Heat``\n simulations.\n 2. Only heat BCs/sources are provided. In this case, only the ``Heat`` equation will be solved.\n Before the simulation starts, it will try to load the heat source from file so a\n previously run ``Conduction`` simulations must have run previously. Since the Conduction\n and ``Heat`` meshes may differ, an interpolation between them will be performed prior to\n starting the ``Heat`` simulation.\n\nAdditional heat sources can be defined, in which case, they will be added on\ntop of the coupling heat source.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatChargeSimulation", + "enum": [ + "HeatChargeSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Heat and Charge sources", + "description": "List of heat and/or charge sources.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatSource": "#/definitions/HeatSource", + "HeatFromElectricSource": "#/definitions/HeatFromElectricSource", + "UniformHeatSource": "#/definitions/UniformHeatSource" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatSource" + }, + { + "$ref": "#/definitions/HeatFromElectricSource" + }, + { + "$ref": "#/definitions/UniformHeatSource" + } + ] + } + }, + "boundary_spec": { + "title": "Boundary Condition Specifications", + "description": "List of boundary condition specifications.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatChargeBoundarySpec": "#/definitions/HeatChargeBoundarySpec", + "HeatBoundarySpec": "#/definitions/HeatBoundarySpec" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatChargeBoundarySpec" + }, + { + "$ref": "#/definitions/HeatBoundarySpec" + } + ] + } + }, + "monitors": { + "title": "Monitors", + "description": "Monitors in the simulation.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureMonitor": "#/definitions/TemperatureMonitor", + "SteadyPotentialMonitor": "#/definitions/SteadyPotentialMonitor", + "SteadyFreeCarrierMonitor": "#/definitions/SteadyFreeCarrierMonitor", + "SteadyEnergyBandMonitor": "#/definitions/SteadyEnergyBandMonitor", + "SteadyElectricFieldMonitor": "#/definitions/SteadyElectricFieldMonitor", + "SteadyCapacitanceMonitor": "#/definitions/SteadyCapacitanceMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureMonitor" + }, + { + "$ref": "#/definitions/SteadyPotentialMonitor" + }, + { + "$ref": "#/definitions/SteadyFreeCarrierMonitor" + }, + { + "$ref": "#/definitions/SteadyEnergyBandMonitor" + }, + { + "$ref": "#/definitions/SteadyElectricFieldMonitor" + }, + { + "$ref": "#/definitions/SteadyCapacitanceMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Grid specification for heat-charge simulation.", + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformUnstructuredGrid": "#/definitions/UniformUnstructuredGrid", + "DistanceUnstructuredGrid": "#/definitions/DistanceUnstructuredGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformUnstructuredGrid" + }, + { + "$ref": "#/definitions/DistanceUnstructuredGrid" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "analysis_spec": { + "title": "Analysis specification.", + "description": "The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/IsothermalSteadyChargeDCAnalysis" + }, + { + "$ref": "#/definitions/UnsteadyHeatAnalysis" + } + ] + } + }, + "required": [ + "size", + "grid_spec" + ], + "additionalProperties": false + }, + "HeatSimulation": { + "title": "HeatSimulation", + "description": "Contains all information about heat simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[MultiPhysicsMedium, Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium, Medium2D, AnisotropicMediumFromMedium2D, FluidSpec, SolidSpec, SolidMedium, FluidMedium, ChargeConductorMedium, ChargeInsulatorMedium, SemiconductorMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, 1], Literal[0, 1], Literal[0, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).\nsources : Tuple[Annotated[Union[tidy3d.components.tcad.source.heat.HeatSource, tidy3d.components.tcad.source.coupled.HeatFromElectricSource, tidy3d.components.tcad.source.heat.UniformHeatSource], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of heat and/or charge sources.\nboundary_spec : Tuple[Annotated[Union[tidy3d.components.tcad.boundary.specification.HeatChargeBoundarySpec, tidy3d.components.tcad.boundary.specification.HeatBoundarySpec], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n List of boundary condition specifications.\nmonitors : Tuple[Annotated[Union[tidy3d.components.tcad.monitors.heat.TemperatureMonitor, tidy3d.components.tcad.monitors.charge.SteadyPotentialMonitor, tidy3d.components.tcad.monitors.charge.SteadyFreeCarrierMonitor, tidy3d.components.tcad.monitors.charge.SteadyEnergyBandMonitor, tidy3d.components.tcad.monitors.charge.SteadyElectricFieldMonitor, tidy3d.components.tcad.monitors.charge.SteadyCapacitanceMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Monitors in the simulation.\ngrid_spec : Union[UniformUnstructuredGrid, DistanceUnstructuredGrid]\n Grid specification for heat-charge simulation.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nanalysis_spec : Union[IsothermalSteadyChargeDCAnalysis, UnsteadyHeatAnalysis] = None\n The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.\n\nExample\n-------\n>>> import tidy3d as td\n>>> heat_sim = td.HeatSimulation( # doctest: +SKIP\n... size=(3.0, 3.0, 3.0),\n... structures=[\n... td.Structure(\n... geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)),\n... medium=td.Medium(\n... permittivity=2.0, heat_spec=td.SolidSpec(\n... conductivity=1,\n... capacity=1,\n... )\n... ),\n... name=\"box\",\n... ),\n... ],\n... medium=td.Medium(permittivity=3.0, heat_spec=td.FluidSpec()),\n... grid_spec=td.UniformUnstructuredGrid(dl=0.1),\n... sources=[td.HeatSource(rate=1, structures=[\"box\"])],\n... boundary_spec=[\n... td.HeatChargeBoundarySpec(\n... placement=td.StructureBoundary(structure=\"box\"),\n... condition=td.TemperatureBC(temperature=500),\n... )\n... ],\n... monitors=[td.TemperatureMonitor(size=(1, 2, 3), name=\"sample\")],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "HeatSimulation", + "enum": [ + "HeatSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "MultiPhysicsMedium": "#/definitions/MultiPhysicsMedium", + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium", + "Medium2D": "#/definitions/Medium2D", + "AnisotropicMediumFromMedium2D": "#/definitions/AnisotropicMediumFromMedium2D", + "FluidSpec": "#/definitions/FluidSpec", + "SolidSpec": "#/definitions/SolidSpec", + "SolidMedium": "#/definitions/SolidMedium", + "FluidMedium": "#/definitions/FluidMedium", + "ChargeConductorMedium": "#/definitions/ChargeConductorMedium", + "ChargeInsulatorMedium": "#/definitions/ChargeInsulatorMedium", + "SemiconductorMedium": "#/definitions/SemiconductorMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/MultiPhysicsMedium" + }, + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + }, + { + "$ref": "#/definitions/Medium2D" + }, + { + "$ref": "#/definitions/AnisotropicMediumFromMedium2D" + }, + { + "$ref": "#/definitions/FluidSpec" + }, + { + "$ref": "#/definitions/SolidSpec" + }, + { + "$ref": "#/definitions/SolidMedium" + }, + { + "$ref": "#/definitions/FluidMedium" + }, + { + "$ref": "#/definitions/ChargeConductorMedium" + }, + { + "$ref": "#/definitions/ChargeInsulatorMedium" + }, + { + "$ref": "#/definitions/SemiconductorMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. Each element can be ``0`` (symmetry off) or ``1`` (symmetry on).", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Heat and Charge sources", + "description": "List of heat and/or charge sources.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatSource": "#/definitions/HeatSource", + "HeatFromElectricSource": "#/definitions/HeatFromElectricSource", + "UniformHeatSource": "#/definitions/UniformHeatSource" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatSource" + }, + { + "$ref": "#/definitions/HeatFromElectricSource" + }, + { + "$ref": "#/definitions/UniformHeatSource" + } + ] + } + }, + "boundary_spec": { + "title": "Boundary Condition Specifications", + "description": "List of boundary condition specifications.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "HeatChargeBoundarySpec": "#/definitions/HeatChargeBoundarySpec", + "HeatBoundarySpec": "#/definitions/HeatBoundarySpec" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/HeatChargeBoundarySpec" + }, + { + "$ref": "#/definitions/HeatBoundarySpec" + } + ] + } + }, + "monitors": { + "title": "Monitors", + "description": "Monitors in the simulation.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "TemperatureMonitor": "#/definitions/TemperatureMonitor", + "SteadyPotentialMonitor": "#/definitions/SteadyPotentialMonitor", + "SteadyFreeCarrierMonitor": "#/definitions/SteadyFreeCarrierMonitor", + "SteadyEnergyBandMonitor": "#/definitions/SteadyEnergyBandMonitor", + "SteadyElectricFieldMonitor": "#/definitions/SteadyElectricFieldMonitor", + "SteadyCapacitanceMonitor": "#/definitions/SteadyCapacitanceMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/TemperatureMonitor" + }, + { + "$ref": "#/definitions/SteadyPotentialMonitor" + }, + { + "$ref": "#/definitions/SteadyFreeCarrierMonitor" + }, + { + "$ref": "#/definitions/SteadyEnergyBandMonitor" + }, + { + "$ref": "#/definitions/SteadyElectricFieldMonitor" + }, + { + "$ref": "#/definitions/SteadyCapacitanceMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Grid specification for heat-charge simulation.", + "discriminator": { + "propertyName": "type", + "mapping": { + "UniformUnstructuredGrid": "#/definitions/UniformUnstructuredGrid", + "DistanceUnstructuredGrid": "#/definitions/DistanceUnstructuredGrid" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/UniformUnstructuredGrid" + }, + { + "$ref": "#/definitions/DistanceUnstructuredGrid" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "analysis_spec": { + "title": "Analysis specification.", + "description": "The `analysis_spec` is used to specify the type of simulation. Currently, it is used to specify Charge simulations or transient Heat simulations.", + "anyOf": [ + { + "$ref": "#/definitions/IsothermalSteadyChargeDCAnalysis" + }, + { + "$ref": "#/definitions/UnsteadyHeatAnalysis" + } + ] + } + }, + "required": [ + "size", + "grid_spec" + ], + "additionalProperties": false + }, + "EMEModeSolverMonitor": { + "title": "EMEModeSolverMonitor", + "description": "EME mode solver monitor.\nRecords EME modes computed in planes intersecting the monitor geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Note: the interval in the propagation direction is not used. Note: this is not yet supported.\neme_cell_interval_space : PositiveInt = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.\nnormalize : bool = True\n Whether to normalize the EME modes to unity flux.\nkeep_invalid_modes : bool = False\n Whether to store modes containing nan values and modes which are exponentially increasing in the propagation direction.\n\nNote\n----\n\n This is different than a :class:`.ModeSolverMonitor`, which computes modes within\n its planar geometry. In contrast, this monitor does not compute new modes; instead,\n it records the modes used for EME expansion and propagation, but only within the\n monitor geometry.\n\nExample\n-------\n>>> monitor = EMEModeSolverMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_modes\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEModeSolverMonitor", + "enum": [ + "EMEModeSolverMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Note: the interval in the propagation direction is not used. Note: this is not yet supported.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.", + "default": true, + "type": "boolean" + }, + "normalize": { + "title": "Normalize Modes", + "description": "Whether to normalize the EME modes to unity flux.", + "default": true, + "type": "boolean" + }, + "keep_invalid_modes": { + "title": "Keep Invalid Modes", + "description": "Whether to store modes containing nan values and modes which are exponentially increasing in the propagation direction.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "EMEFieldMonitor": { + "title": "EMEFieldMonitor", + "description": "EME monitor for propagated field.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\ninterval_space : Tuple[PositiveInt, PositiveInt, PositiveInt] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. For 'EMEFieldMonitor', refers to the number of modes at each port.Cannot exceed the max of the number of modes in the two ports. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\neme_cell_interval_space : Literal[1] = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1. Note: this field is not used for EME field monitor.\n\nExample\n-------\n>>> monitor = EMEFieldMonitor(\n... center=(1,2,3),\n... size=(2,2,0),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_field\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEFieldMonitor", + "enum": [ + "EMEFieldMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + }, + { + "type": "integer", + "exclusiveMinimum": 0 + } + ] + }, + "colocate": { + "title": "Colocate Fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default (False) is used internally in EME propagation.", + "default": true, + "type": "boolean" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. For 'EMEFieldMonitor', refers to the number of modes at each port.Cannot exceed the max of the number of modes in the two ports. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1. Note: this field is not used for EME field monitor.", + "default": 1, + "enum": [ + 1 + ], + "type": "integer" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "EMECoefficientMonitor": { + "title": "EMECoefficientMonitor", + "description": "EME monitor for mode coefficients.\nRecords the amplitudes of the forward and backward modes in each cell\nintersecting the monitor geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1], NoneType] = None\n Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.\nnum_modes : Optional[NonNegativeInt] = None\n Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.\nnum_sweep : Optional[NonNegativeInt] = 1\n Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.\ninterval_space : Tuple[Literal[1], Literal[1], Literal[1]] = (1, 1, 1)\n Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1. Note: This field is not used for 'EMECoefficientMonitor'.\neme_cell_interval_space : PositiveInt = 1\n Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.\ncolocate : Literal[True] = True\n Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid) on-the-fly during a solver run. Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.\n\nExample\n-------\n>>> monitor = EMECoefficientMonitor(\n... center=(1,2,3),\n... size=(2,2,2),\n... freqs=[300e12],\n... num_modes=2,\n... name=\"eme_coeffs\"\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMECoefficientMonitor", + "enum": [ + "EMECoefficientMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "freqs": { + "title": "Monitor Frequencies", + "description": "Frequencies at which the monitor will record. Must be a subset of the simulation 'freqs'. A value of 'None' will record at all simulation 'freqs'.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "num_modes": { + "title": "Number of Modes", + "description": "Maximum number of modes for the monitor to record. Cannot exceed the greatest number of modes in any EME cell. A value of 'None' will record all modes.", + "minimum": 0, + "type": "integer" + }, + "num_sweep": { + "title": "Number of Sweep Indices", + "description": "Number of sweep indices for the monitor to record. Cannot exceed the number of sweep indices for the simulation. If the sweep does not change the monitor data, the sweep index will be omitted. A value of 'None' will record all sweep indices.", + "default": 1, + "minimum": 0, + "type": "integer" + }, + "interval_space": { + "title": "Spatial Interval", + "description": "Number of grid step intervals between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last point of the monitor grid are always included. Not all monitors support values different from 1. Note: This field is not used for 'EMECoefficientMonitor'.", + "default": [ + 1, + 1, + 1 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + }, + { + "enum": [ + 1 + ], + "type": "integer" + } + ] + }, + "eme_cell_interval_space": { + "title": "EME Cell Interval", + "description": "Number of eme cells between monitor recordings. If equal to 1, there will be no downsampling. If greater than 1, the step will be applied, but the first and last cells are always included. Not used in all monitors. Not all monitors support values different from 1.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "colocate": { + "title": "Colocate Fields", + "description": "Defines whether fields are colocated to grid cell boundaries (i.e. to the primal grid) on-the-fly during a solver run. Can be toggled for field recording monitors and is hard-coded for other monitors depending on their specific function.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "EMEModeSpec": { + "title": "EMEModeSpec", + "description": "Mode spec for EME cells. Overrides some of the defaults and allowed values.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : PositiveInt = 1\n Number of modes returned by mode solver.\ntarget_neff : Optional[PositiveFloat] = None\n Guess for effective index of the mode.\nnum_pml : Tuple[NonNegativeInt, NonNegativeInt] = (0, 0)\n Number of standard pml layers to add in the two tangential axes.\nfilter_pol : Optional[Literal['te', 'tm']] = None\n The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.\nangle_theta : Literal[0.0] = 0.0\n [units = rad]. Polar angle of the propagation axis from the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.\nangle_phi : Literal[0.0] = 0.0\n [units = rad]. Azimuth angle of the propagation axis in the plane orthogonal to the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.\nprecision : Literal['auto', 'single', 'double'] = auto\n The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.\nbend_radius : Optional[float] = None\n [units = um]. A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.\nbend_axis : Optional[Literal[0, 1]] = None\n Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).\nangle_rotation : bool = False\n Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.\ntrack_freq : Optional[Literal['central', 'lowest', 'highest']] = None\n Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed, which is the default for best performance.\ngroup_index_step : Union[PositiveFloat, bool] = False\n Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_modes": { + "title": "Number of modes", + "description": "Number of modes returned by mode solver.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "target_neff": { + "title": "Target effective index", + "description": "Guess for effective index of the mode.", + "exclusiveMinimum": 0, + "type": "number" + }, + "num_pml": { + "title": "Number of PML layers", + "description": "Number of standard pml layers to add in the two tangential axes.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "integer", + "minimum": 0 + }, + { + "type": "integer", + "minimum": 0 + } + ] + }, + "filter_pol": { + "title": "Polarization filtering", + "description": "The solver always computes the ``num_modes`` modes closest to the given ``target_neff``. If ``filter_pol==None``, they are simply sorted in order of decreasing effective index. If a polarization filter is selected, the modes are rearranged such that the first ``n_pol`` modes in the list are the ones with the selected polarization fraction larger than or equal to 0.5, while the next ``num_modes - n_pol`` modes are the ones where it is smaller than 0.5 (i.e. the opposite polarization fraction is larger than 0.5). Within each polarization subset, the modes are still ordered by decreasing effective index. ``te``-fraction is defined as the integrated intensity of the E-field component parallel to the first plane axis, normalized to the total in-plane E-field intensity. Conversely, ``tm``-fraction uses the E field component parallel to the second plane axis.", + "enum": [ + "te", + "tm" + ], + "type": "string" + }, + "angle_theta": { + "title": "Polar Angle", + "description": "Polar angle of the propagation axis from the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.", + "default": 0.0, + "units": "rad", + "enum": [ + 0.0 + ], + "type": "number" + }, + "angle_phi": { + "title": "Azimuth Angle", + "description": "Azimuth angle of the propagation axis in the plane orthogonal to the injection axis. Not currently supported in EME cells. Use an additional 'ModeSolverMonitor' and 'sim_data.smatrix_in_basis' to achieve off-normal injection in EME.", + "default": 0.0, + "units": "rad", + "enum": [ + 0.0 + ], + "type": "number" + }, + "precision": { + "title": "single, double, or automatic precision in mode solver", + "description": "The solver will be faster and using less memory under single precision, but more accurate under double precision. Choose ``'auto'`` to apply double precision if the simulation contains a good conductor, single precision otherwise.", + "default": "auto", + "enum": [ + "auto", + "single", + "double" + ], + "type": "string" + }, + "bend_radius": { + "title": "Bend radius", + "description": "A curvature radius for simulation of waveguide bends. Can be negative, in which case the mode plane center has a smaller value than the curvature center along the tangential axis perpendicular to the bend axis.", + "units": "um", + "type": "number" + }, + "bend_axis": { + "title": "Bend axis", + "description": "Index into the two tangential axes defining the normal to the plane in which the bend lies. This must be provided if ``bend_radius`` is not ``None``. For example, for a ring in the global xy-plane, and a mode plane in either the xz or the yz plane, the ``bend_axis`` is always 1 (the global z axis).", + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "angle_rotation": { + "title": "Use fields rotation when angle_theta is not zero", + "description": "Defines how modes are computed when angle_theta is not zero. If 'False', a coordinate transformation is applied through the permittivity and permeability tensors.If 'True', the structures in the simulation are first rotated to compute a mode solution at a reference plane normal to the structure's azimuthal direction. Then, the fields are rotated to align with the mode plane, using the 'n_eff' calculated at the reference plane. The second option can produce more accurate results, but more care must be taken, for example, in ensuring that the original mode plane intersects the correct geometries in the simulation with rotated structures. Note: currently only supported when 'angle_phi' is a multiple of 'np.pi'.", + "default": false, + "type": "boolean" + }, + "track_freq": { + "title": "Mode Tracking Frequency", + "description": "Parameter that turns on/off mode tracking based on their similarity. Can take values ``'lowest'``, ``'central'``, or ``'highest'``, which correspond to mode tracking based on the lowest, central, or highest frequency. If ``None`` no mode tracking is performed, which is the default for best performance.", + "enum": [ + "central", + "lowest", + "highest" + ], + "type": "string" + }, + "group_index_step": { + "title": "Frequency step for group index computation", + "description": "Control the computation of the group index alongside the effective index. If set to a positive value, it sets the fractional frequency step used in the numerical differentiation of the effective index to compute the group index. If set to `True`, the default of 0.005 is used.", + "default": false, + "anyOf": [ + { + "type": "number", + "exclusiveMinimum": 0 + }, + { + "type": "boolean" + } + ] + }, + "type": { + "title": "Type", + "default": "EMEModeSpec", + "enum": [ + "EMEModeSpec" + ], + "type": "string" + } + }, + "additionalProperties": false + }, + "EMEUniformGrid": { + "title": "EMEUniformGrid", + "description": "Specification for a uniform EME grid.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nnum_cells : PositiveInt\n Number of cells in the uniform EME grid.\nmode_spec : EMEModeSpec\n Mode specification for the uniform EME grid.\n\nExample\n-------\n>>> from tidy3d import EMEModeSpec\n>>> mode_spec = EMEModeSpec(num_modes=10)\n>>> eme_grid = EMEUniformGrid(num_cells=10, mode_spec=mode_spec)", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMEUniformGrid", + "enum": [ + "EMEUniformGrid" + ], + "type": "string" + }, + "num_cells": { + "title": "Number of cells", + "description": "Number of cells in the uniform EME grid.", + "exclusiveMinimum": 0, + "type": "integer" + }, + "mode_spec": { + "title": "Mode Specification", + "description": "Mode specification for the uniform EME grid.", + "allOf": [ + { + "$ref": "#/definitions/EMEModeSpec" + } + ] + } + }, + "required": [ + "num_cells", + "mode_spec" + ], + "additionalProperties": false + }, + "EMEExplicitGrid": { + "title": "EMEExplicitGrid", + "description": "EME grid with explicitly defined internal boundaries.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nmode_specs : List[EMEModeSpec]\n Mode specifications for each cell in the explicit EME grid.\nboundaries : ArrayLike[dtype=float, ndim=1]\n List of coordinates of internal cell boundaries along the propagation axis. Must contain one fewer item than 'mode_specs', and must be strictly increasing. Each cell spans the region between an adjacent pair of boundaries. The first (last) cell spans the region between the first (last) boundary and the simulation boundary.\n\nExample\n-------\n>>> from tidy3d import EMEExplicitGrid, EMEModeSpec\n>>> mode_spec1 = EMEModeSpec(num_modes=10)\n>>> mode_spec2 = EMEModeSpec(num_modes=20)\n>>> eme_grid = EMEExplicitGrid(\n... mode_specs=[mode_spec1, mode_spec2],\n... boundaries=[1],\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMEExplicitGrid", + "enum": [ + "EMEExplicitGrid" + ], + "type": "string" + }, + "mode_specs": { + "title": "Mode Specifications", + "description": "Mode specifications for each cell in the explicit EME grid.", + "type": "array", + "items": { + "$ref": "#/definitions/EMEModeSpec" + } + }, + "boundaries": { + "title": "Boundaries", + "description": "List of coordinates of internal cell boundaries along the propagation axis. Must contain one fewer item than 'mode_specs', and must be strictly increasing. Each cell spans the region between an adjacent pair of boundaries. The first (last) cell spans the region between the first (last) boundary and the simulation boundary.", + "type": "ArrayLike" + } + }, + "required": [ + "mode_specs", + "boundaries" + ], + "additionalProperties": false + }, + "EMECompositeGrid": { + "title": "EMECompositeGrid", + "description": "EME grid made out of multiple subgrids.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : PositiveInt = 1\n Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.\nname : Optional[str] = None\n Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.\nsubgrids : ForwardRef('list[EMESubgridType]')\n Subgrids in the composite grid.\nsubgrid_boundaries : ArrayLike[dtype=float, ndim=1]\n List of coordinates of internal subgrid boundaries along the propagation axis. Must contain one fewer item than 'subgrids', and must be strictly increasing. Each subgrid spans the region between an adjacent pair of subgrid boundaries. The first (last) subgrid spans the region between the first (last) subgrid boundary and the simulation boundary.\n\nExample\n-------\n>>> from tidy3d import EMEUniformGrid, EMEModeSpec\n>>> mode_spec1 = EMEModeSpec(num_modes=10)\n>>> mode_spec2 = EMEModeSpec(num_modes=20)\n>>> subgrid1 = EMEUniformGrid(num_cells=5, mode_spec=mode_spec1)\n>>> subgrid2 = EMEUniformGrid(num_cells=10, mode_spec=mode_spec2)\n>>> eme_grid = EMECompositeGrid(\n... subgrids=[subgrid1, subgrid2],\n... subgrid_boundaries=[1]\n... )", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of this EME grid. Useful for efficiently simulating long periodic structures like Bragg gratings. Instead of explicitly repeating the cells, setting 'num_reps' allows the EME solver to reuse the modes and cell interface scattering matrices.", + "default": 1, + "exclusiveMinimum": 0, + "type": "integer" + }, + "name": { + "title": "Name", + "description": "Name of this 'EMEGridSpec'. Used in 'EMEPeriodicitySweep'.", + "type": "string" + }, + "type": { + "title": "Type", + "default": "EMECompositeGrid", + "enum": [ + "EMECompositeGrid" + ], + "type": "string" + }, + "subgrids": { + "title": "Subgrids", + "description": "Subgrids in the composite grid.", + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/EMEUniformGrid" + }, + { + "$ref": "#/definitions/EMEExplicitGrid" + }, + { + "$ref": "#/definitions/EMECompositeGrid" + } + ] + } + }, + "subgrid_boundaries": { + "title": "Subgrid Boundaries", + "description": "List of coordinates of internal subgrid boundaries along the propagation axis. Must contain one fewer item than 'subgrids', and must be strictly increasing. Each subgrid spans the region between an adjacent pair of subgrid boundaries. The first (last) subgrid spans the region between the first (last) subgrid boundary and the simulation boundary.", + "type": "ArrayLike" + } + }, + "required": [ + "subgrids", + "subgrid_boundaries" + ], + "additionalProperties": false + }, + "EMELengthSweep": { + "title": "EMELengthSweep", + "description": "Spec for sweeping EME cell lengths.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nscale_factors : ArrayLike\n Length scale factors to be used in the EME propagation step. The EME propagation step is repeated after scaling every cell length by this amount. The results are stored in 'sim_data.smatrix'. If a 2D array is provided, the first index is the sweep index and the second index is the cell index, allowing a nonuniform cell scaling along the propagation axis.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMELengthSweep", + "enum": [ + "EMELengthSweep" + ], + "type": "string" + }, + "scale_factors": { + "title": "Length Scale Factor", + "description": "Length scale factors to be used in the EME propagation step. The EME propagation step is repeated after scaling every cell length by this amount. The results are stored in 'sim_data.smatrix'. If a 2D array is provided, the first index is the sweep index and the second index is the cell index, allowing a nonuniform cell scaling along the propagation axis.", + "type": "ArrayLike" + } + }, + "required": [ + "scale_factors" + ], + "additionalProperties": false + }, + "EMEModeSweep": { + "title": "EMEModeSweep", + "description": "Spec for sweeping number of modes in EME propagation step.\nUsed for convergence testing.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_modes : ArrayLike[dtype=int, ndim=1]\n Max number of modes to use in the EME propagation step. The EME propagation step is repeated after dropping modes with mode_index exceeding this value. This can be used for convergence testing; reliable results should be independent of the number of modes used. This value cannot exceed the maximum number of modes in any EME cell in the simulation.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEModeSweep", + "enum": [ + "EMEModeSweep" + ], + "type": "string" + }, + "num_modes": { + "title": "Number of Modes", + "description": "Max number of modes to use in the EME propagation step. The EME propagation step is repeated after dropping modes with mode_index exceeding this value. This can be used for convergence testing; reliable results should be independent of the number of modes used. This value cannot exceed the maximum number of modes in any EME cell in the simulation.", + "type": "ArrayLike" + } + }, + "required": [ + "num_modes" + ], + "additionalProperties": false + }, + "EMEFreqSweep": { + "title": "EMEFreqSweep", + "description": "Spec for sweeping frequency in EME propagation step.\nUnlike ``sim.freqs``, the frequency sweep is approximate, using a\nperturbative mode solver relative to the simulation EME modes.\nThis can be a faster way to solve at a larger number of frequencies.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nfreq_scale_factors : ArrayLike[dtype=float, ndim=1]\n Scale factors applied to every frequency in 'EMESimulation.freqs'. After applying the scale factors, the new modes are computed approximately using the exact modes as a basis. If there are multiple 'EMESimulation.freqs', the exact modes are computed at each of those frequencies, and then the scale factors are applied to each independently.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEFreqSweep", + "enum": [ + "EMEFreqSweep" + ], + "type": "string" + }, + "freq_scale_factors": { + "title": "Frequency Scale Factors", + "description": "Scale factors applied to every frequency in 'EMESimulation.freqs'. After applying the scale factors, the new modes are computed approximately using the exact modes as a basis. If there are multiple 'EMESimulation.freqs', the exact modes are computed at each of those frequencies, and then the scale factors are applied to each independently.", + "type": "ArrayLike" + } + }, + "required": [ + "freq_scale_factors" + ], + "additionalProperties": false + }, + "EMEPeriodicitySweep": { + "title": "EMEPeriodicitySweep", + "description": "Spec for sweeping number of repetitions of EME subgrids.\nUseful for simulating long periodic structures like Bragg gratings,\nas it allows the EME solver to reuse the modes and cell interface\nscattering matrices.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nnum_reps : List[dict[str, pydantic.v1.types.PositiveInt]]\n Number of periodic repetitions of named subgrids in this EME grid. At each sweep index, contains a dict mapping the name of a subgrid to the number of repetitions of that subgrid at that sweep index.\n\nCompared to setting ``num_reps`` directly in the ``eme_grid_spec``,\nthis sweep spec allows varying the number of repetitions,\neffectively simulating multiple structures in a single EME simulation.\n\nExample\n-------\n>>> n_list = [1, 50, 100]\n>>> sweep_spec = EMEPeriodicitySweep(num_reps=[{\"unit_cell\": n} for n in n_list])", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMEPeriodicitySweep", + "enum": [ + "EMEPeriodicitySweep" + ], + "type": "string" + }, + "num_reps": { + "title": "Number of Repetitions", + "description": "Number of periodic repetitions of named subgrids in this EME grid. At each sweep index, contains a dict mapping the name of a subgrid to the number of repetitions of that subgrid at that sweep index.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "integer", + "exclusiveMinimum": 0 + } + } + } + }, + "required": [ + "num_reps" + ], + "additionalProperties": false + }, + "EMESimulation": { + "title": "EMESimulation", + "description": "EigenMode Expansion (EME) simulation.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. \nsources : Tuple[NoneType, ...] = ()\n Sources in the simulation. NOTE: sources are not currently supported for EME simulations. Instead, the simulation performs full bidirectional propagation in the 'port_mode' basis. After running the simulation, use 'smatrix_in_basis' to use another set of modes or input field.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), y=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), z=Boundary(attrs={},, plus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, minus=PECBoundary(attrs={},, name=None,, type='PECBoundary'),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. By default, PEC boundary conditions are applied on all sides. This field is for consistency with FDTD simulations; however, please note that regardless of the 'boundary_spec', the mode solver terminates the mode plane with PEC boundary. The 'EMEModeSpec' can be used to apply PML layers in the mode solver.\nmonitors : Tuple[Annotated[Union[tidy3d.components.eme.monitor.EMEModeSolverMonitor, tidy3d.components.eme.monitor.EMEFieldMonitor, tidy3d.components.eme.monitor.EMECoefficientMonitor, tidy3d.components.monitor.ModeSolverMonitor, tidy3d.components.monitor.PermittivityMonitor], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions. This is distinct from 'eme_grid_spec', which defines the 1D EME grid in the propagation direction.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.\nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n Frequencies for the EME simulation. The field is propagated independently at each provided frequency. This can be slow when the number of frequencies is large. In this case, consider using the approximate 'EMEFreqSweep' as the 'sweep_spec' instead of providing all desired frequencies here.\naxis : Literal[0, 1, 2]\n Propagation axis (0, 1, or 2) for the EME simulation.\neme_grid_spec : Union[EMEUniformGrid, EMECompositeGrid, EMEExplicitGrid]\n Specification for the EME propagation grid. The simulation is divided into cells in the propagation direction; this parameter specifies the layout of those cells. Mode solving is performed in each cell, and then propagation between cells is performed to determine the complete solution. This is distinct from 'grid_spec', which defines the grid in the two tangential directions, as well as the grid used for field monitors.\nstore_port_modes : bool = True\n Whether to store the modes associated with the two ports. Required to find scattering matrix in basis besides the computational basis.\nnormalize : bool = True\n Whether to normalize the port modes to unity flux, thereby normalizing the scattering matrix and expansion coefficients.\nport_offsets : Tuple[NonNegativeFloat, NonNegativeFloat] = (0, 0)\n Offsets for the two ports, relative to the simulation bounds along the propagation axis.\nsweep_spec : Union[EMELengthSweep, EMEModeSweep, EMEFreqSweep, EMEPeriodicitySweep, NoneType] = None\n Specification for a parameter sweep to be performed during the EME propagation step. The results are stored in 'sim_data.smatrix'. Other simulation monitor data is not included in the sweep.\nconstraint : Optional[Literal['passive', 'unitary']] = passive\n Constraint for EME propagation, imposed at cell interfaces. A constraint of 'passive' means that energy can be dissipated but not created at interfaces. A constraint of 'unitary' means that energy is conserved at interfaces (but not necessarily within cells). The option 'none' may be faster for a large number of modes. The option 'passive' can serve as regularization for the field continuity requirement and give more physical results.\n\nNotes\n-----\n\n EME is a frequency-domain method for propagating the electromagnetic field along a\n specified axis. The method is well-suited for propagation of guided waves.\n The electromagnetic fields are expanded locally in the basis of eigenmodes of the\n waveguide; they are then propagated by imposing continuity conditions in this basis.\n\n The EME simulation is performed along the propagation axis ``axis`` at frequencies ``freqs``.\n The simulation is divided into cells along the propagation axis, as defined by\n ``eme_grid_spec``. Mode solving is performed at cell centers, and boundary conditions are\n imposed between cells. The EME ports are defined to be the boundaries of the first and last\n cell in the EME grid. These can be moved using ``port_offsets``.\n\n An EME simulation always computes the full scattering matrix of the structure.\n Additional data can be recorded by adding 'monitors' to the simulation.\n\n **Other Bases**\n\n By default, the scattering matrix is expressed in the basis of EME modes at the two ports. It is sometimes useful to use alternative bases. For example, in a waveguide splitter, we might want the scattering matrix in the basis of modes of the individual waveguides. The functions `smatrix_in_basis` and `field_in_basis` in :class:`.EMESimulationData` can be used for this purpose after the simulation has been run.\n\n **Frequency Sweeps**\n\n Frequency sweeps are supported by including multiple frequencies in the `freqs` field. However, our EME solver repeats the mode solving for each new frequency, so frequency sweeps involving a large number of frequencies can be slow and expensive. If a large number of frequencies are required, consider using our FDTD solver instead.\n\n **Passivity and Unitarity Constraints**\n\n Passivity and unitarity constraints can be imposed via the `constraint` field. These constraints are imposed at interfaces between cells, possibly at the expense of field continuity. Passivity means that the interface can only dissipate energy, and unitarity means the interface will conserve energy (energy may still be dissipated inside cells when the propagation constant is complex). Adding constraints can slow down the simulation significantly, especially for a large number of modes (more than 30 or 40).\n\n **Too Many Modes**\n\n It is important to use enough modes to capture the physics of the device and to ensure that the results have converged (see below). However, using too many modes can slow down the simulation and result in numerical issues. If too many modes are used, it is common to see a warning about invalid modes in the simulation log. While these modes are not included in the EME propagation, this can indicate some other issue with the setup, especially if the results have not converged. In this case, extending the simulation size in the transverse directions and increasing the grid resolution may help by creating more valid modes that can be used in convergence testing.\n\n **Mode Convergence Sweeps**\n\n It is a good idea to check that the number of modes is large enough by running a mode convergence sweep. This can be done using :class:`.EMEModeSweep`.\n\nExample\n-------\n>>> from tidy3d import Box, Medium, Structure, C_0, inf\n>>> from tidy3d import EMEModeSpec, EMEUniformGrid, GridSpec\n>>> from tidy3d import EMEFieldMonitor\n>>> lambda0 = 1550e-9\n>>> freq0 = C_0 / lambda0\n>>> sim_size = 3*lambda0, 3*lambda0, 3*lambda0\n>>> waveguide_size = (lambda0/2, lambda0, inf)\n>>> waveguide = Structure(\n... geometry=Box(center=(0,0,0), size=waveguide_size),\n... medium=Medium(permittivity=2)\n... )\n>>> eme_grid_spec = EMEUniformGrid(num_cells=5, mode_spec=EMEModeSpec(num_modes=10))\n>>> grid_spec = GridSpec(wavelength=lambda0)\n>>> field_monitor = EMEFieldMonitor(\n... size=(0, sim_size[1], sim_size[2]),\n... name=\"field_monitor\"\n... )\n>>> sim = EMESimulation(\n... size=sim_size,\n... monitors=[field_monitor],\n... structures=[waveguide],\n... axis=2,\n... freqs=[freq0],\n... eme_grid_spec=eme_grid_spec,\n... grid_spec=grid_spec\n... )\n\nSee Also\n--------\n\n**Notebooks:**\n * `EME Solver Demonstration <../../notebooks/docs/features/eme.rst>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "EMESimulation", + "enum": [ + "EMESimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to vacuum if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. ", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Sources", + "description": "Sources in the simulation. NOTE: sources are not currently supported for EME simulations. Instead, the simulation performs full bidirectional propagation in the 'port_mode' basis. After running the simulation, use 'smatrix_in_basis' to use another set of modes or input field.", + "default": [], + "type": "array", + "items": { + "type": "null" + } + }, + "boundary_spec": { + "title": "Boundaries", + "description": "Specification of boundary conditions along each dimension. By default, PEC boundary conditions are applied on all sides. This field is for consistency with FDTD simulations; however, please note that regardless of the 'boundary_spec', the mode solver terminates the mode plane with PEC boundary. The 'EMEModeSpec' can be used to apply PML layers in the mode solver.", + "default": { + "attrs": {}, + "x": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "y": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "z": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PECBoundary" + }, + "type": "Boundary" + }, + "type": "BoundarySpec" + }, + "allOf": [ + { + "$ref": "#/definitions/BoundarySpec" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "EMEModeSolverMonitor": "#/definitions/EMEModeSolverMonitor", + "EMEFieldMonitor": "#/definitions/EMEFieldMonitor", + "EMECoefficientMonitor": "#/definitions/EMECoefficientMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor", + "PermittivityMonitor": "#/definitions/PermittivityMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/EMEModeSolverMonitor" + }, + { + "$ref": "#/definitions/EMEFieldMonitor" + }, + { + "$ref": "#/definitions/EMECoefficientMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + }, + { + "$ref": "#/definitions/PermittivityMonitor" + } + ] + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Specifications for the simulation grid along each of the three directions. This is distinct from 'eme_grid_spec', which defines the 1D EME grid in the propagation direction.", + "default": { + "attrs": {}, + "grid_x": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_y": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_z": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "wavelength": null, + "override_structures": [], + "snapping_points": [], + "layer_refinement_specs": [], + "type": "GridSpec" + }, + "validate_default": true, + "allOf": [ + { + "$ref": "#/definitions/GridSpec" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "lumped_elements": { + "title": "Lumped Elements", + "description": "Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "LumpedResistor": "#/definitions/LumpedResistor", + "CoaxialLumpedResistor": "#/definitions/CoaxialLumpedResistor", + "LinearLumpedElement": "#/definitions/LinearLumpedElement" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LumpedResistor" + }, + { + "$ref": "#/definitions/CoaxialLumpedResistor" + }, + { + "$ref": "#/definitions/LinearLumpedElement" + } + ] + } + }, + "subpixel": { + "title": "Subpixel Averaging", + "description": "Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.", + "default": { + "attrs": {}, + "dielectric": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "metal": { + "attrs": {}, + "type": "Staircasing" + }, + "pec": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" + }, + "lossy_metal": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "type": "SubpixelSpec" + }, + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/SubpixelSpec" + } + ] + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.", + "default": "tidy3d", + "enum": [ + "autograd_fwd", + "autograd_bwd", + "tidy3d" + ], + "type": "string" + }, + "post_norm": { + "title": "Post Normalization Values", + "description": "Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.", + "default": 1.0, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "freqs": { + "title": "Frequencies", + "description": "Frequencies for the EME simulation. The field is propagated independently at each provided frequency. This can be slow when the number of frequencies is large. In this case, consider using the approximate 'EMEFreqSweep' as the 'sweep_spec' instead of providing all desired frequencies here.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "axis": { + "title": "Propagation Axis", + "description": "Propagation axis (0, 1, or 2) for the EME simulation.", + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "eme_grid_spec": { + "title": "EME Grid Specification", + "description": "Specification for the EME propagation grid. The simulation is divided into cells in the propagation direction; this parameter specifies the layout of those cells. Mode solving is performed in each cell, and then propagation between cells is performed to determine the complete solution. This is distinct from 'grid_spec', which defines the grid in the two tangential directions, as well as the grid used for field monitors.", + "anyOf": [ + { + "$ref": "#/definitions/EMEUniformGrid" + }, + { + "$ref": "#/definitions/EMECompositeGrid" + }, + { + "$ref": "#/definitions/EMEExplicitGrid" + } + ] + }, + "store_port_modes": { + "title": "Store Port Modes", + "description": "Whether to store the modes associated with the two ports. Required to find scattering matrix in basis besides the computational basis.", + "default": true, + "type": "boolean" + }, + "normalize": { + "title": "Normalize Scattering Matrix", + "description": "Whether to normalize the port modes to unity flux, thereby normalizing the scattering matrix and expansion coefficients.", + "default": true, + "type": "boolean" + }, + "port_offsets": { + "title": "Port Offsets", + "description": "Offsets for the two ports, relative to the simulation bounds along the propagation axis.", + "default": [ + 0, + 0 + ], + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "number", + "minimum": 0 + }, + { + "type": "number", + "minimum": 0 + } + ] + }, + "sweep_spec": { + "title": "EME Sweep Specification", + "description": "Specification for a parameter sweep to be performed during the EME propagation step. The results are stored in 'sim_data.smatrix'. Other simulation monitor data is not included in the sweep.", + "anyOf": [ + { + "$ref": "#/definitions/EMELengthSweep" + }, + { + "$ref": "#/definitions/EMEModeSweep" + }, + { + "$ref": "#/definitions/EMEFreqSweep" + }, + { + "$ref": "#/definitions/EMEPeriodicitySweep" + } + ] + }, + "constraint": { + "title": "EME Constraint", + "description": "Constraint for EME propagation, imposed at cell interfaces. A constraint of 'passive' means that energy can be dissipated but not created at interfaces. A constraint of 'unitary' means that energy is conserved at interfaces (but not necessarily within cells). The option 'none' may be faster for a large number of modes. The option 'passive' can serve as regularization for the field continuity requirement and give more physical results.", + "default": "passive", + "enum": [ + "passive", + "unitary" + ], + "type": "string" + } + }, + "required": [ + "size", + "freqs", + "axis", + "eme_grid_spec" + ], + "additionalProperties": false + }, + "ModeSolver": { + "title": "ModeSolver", + "description": "Interface for solving electromagnetic eigenmodes in a 2D plane with translational\ninvariance in the third dimension.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsimulation : Union[Simulation, EMESimulation]\n Simulation or EMESimulation defining all structures and mediums.\nplane : Union[Box, ModeSource, ModeMonitor, ModeSolverMonitor]\n Cross-sectional plane in which the mode will be computed.\nmode_spec : ModeSpec\n Container with specifications about the modes to be solved for.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n A list of frequencies at which to solve.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\n\nSee Also\n--------\n\n:class:`ModeSource`:\n Injects current source to excite modal profile on finite extent plane.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "simulation": { + "title": "Simulation", + "description": "Simulation or EMESimulation defining all structures and mediums.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Simulation": "#/definitions/Simulation", + "EMESimulation": "#/definitions/EMESimulation" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Simulation" + }, + { + "$ref": "#/definitions/EMESimulation" + } + ] + }, + "plane": { + "title": "Plane", + "description": "Cross-sectional plane in which the mode will be computed.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "ModeSource": "#/definitions/ModeSource", + "ModeMonitor": "#/definitions/ModeMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/ModeSource" + }, + { + "$ref": "#/definitions/ModeMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + } + ] + }, + "mode_spec": { + "title": "Mode specification", + "description": "Container with specifications about the modes to be solved for.", + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "freqs": { + "title": "Frequencies", + "description": "A list of frequencies at which to solve.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "direction": { + "title": "Propagation direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "colocate": { + "title": "Colocate fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.", + "default": true, + "type": "boolean" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "type": { + "title": "Type", + "default": "ModeSolver", + "enum": [ + "ModeSolver" + ], + "type": "string" + } + }, + "required": [ + "simulation", + "plane", + "mode_spec", + "freqs" + ], + "additionalProperties": false + }, + "ModeSimulation": { + "title": "ModeSimulation", + "description": "Simulation class for solving electromagnetic eigenmodes in a 2D plane with\ntranslational invariance in the third dimension. If the field ``plane`` is\nspecified, the domain for mode solving is the intersection between the ``plane``\nand the simulation geometry. If the simulation geometry is 2D (has zero size\nin one dimension) and the ``plane`` is ``None``, then the domain for mode solving\nis the entire 2D geometry.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nmedium : Union[Medium, AnisotropicMedium, PECMedium, PMCMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, FullyAnisotropicMedium, CustomMedium, CustomPoleResidue, CustomSellmeier, CustomLorentz, CustomDebye, CustomDrude, CustomAnisotropicMedium, PerturbationMedium, PerturbationPoleResidue, LossyMetalMedium] = Medium(attrs={}, name=None, frequency_range=None, allow_gain=False, nonlinear_spec=None, modulation_spec=None, viz_spec=None, heat_spec=None, type='Medium', permittivity=1.0, conductivity=0.0)\n Background medium of simulation, defaults to vacuum if not specified.\nstructures : Tuple[Structure, ...] = ()\n Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.\nsymmetry : Tuple[Literal[0, -1, 1], Literal[0, -1, 1], Literal[0, -1, 1]] = (0, 0, 0)\n Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. \nsources : Tuple[] = ()\n Sources in the simulation. Note: sources are not supported in mode simulations.\nboundary_spec : BoundarySpec = BoundarySpec(attrs={}, x=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), y=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), z=Boundary(attrs={},, plus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, minus=PML(attrs={},, name=None,, type='PML',, num_layers=12,, parameters=PMLParams(attrs={},, sigma_order=3,, sigma_min=0.0,, sigma_max=1.5,, type='PMLParams',, kappa_order=3,, kappa_min=1.0,, kappa_max=3.0,, alpha_order=1,, alpha_min=0.0,, alpha_max=0.0)),, type='Boundary'), type='BoundarySpec')\n Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides. This behavior is for consistency with FDTD simulations; however, please note that the mode solver terminates the mode plane with PEC boundary. The 'ModeSpec' can be used to apply PML layers in the mode solver.\nmonitors : Tuple[PermittivityMonitor, ...] = ()\n Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.\ngrid_spec : GridSpec = GridSpec(attrs={}, grid_x=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_y=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), grid_z=AutoGrid(attrs={},, type='AutoGrid',, max_scale=1.4,, mesher=GradedMesher(attrs={},, type='GradedMesher'),, dl_min=None,, min_steps_per_wvl=10.0,, min_steps_per_sim_size=10.0), wavelength=None, override_structures=(), snapping_points=(), layer_refinement_specs=(), type='GridSpec')\n Specifications for the simulation grid along each of the three directions.\nversion : str = 2.9.0\n String specifying the front end version number.\nplot_length_units : Optional[Literal['nm', '\u03bcm', 'um', 'mm', 'cm', 'm']] = \u03bcm\n When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.\nstructure_priority_mode : Literal['equal', 'conductor'] = equal\n This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.\nlumped_elements : Tuple[Annotated[Union[tidy3d.components.lumped_element.LumpedResistor, tidy3d.components.lumped_element.CoaxialLumpedResistor, tidy3d.components.lumped_element.LinearLumpedElement], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})], ...] = ()\n Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.\nsubpixel : Union[bool, SubpixelSpec] = SubpixelSpec(attrs={}, dielectric=PolarizedAveraging(attrs={},, type='PolarizedAveraging'), metal=Staircasing(attrs={},, type='Staircasing'), pec=PECConformal(attrs={},, type='PECConformal',, timestep_reduction=0.3,, edge_singularity_correction=False), pmc=Staircasing(attrs={},, type='Staircasing'), lossy_metal=SurfaceImpedance(attrs={},, type='SurfaceImpedance',, timestep_reduction=0.0,, edge_singularity_correction=False), type='SubpixelSpec')\n Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.\nsimulation_type : Optional[Literal['autograd_fwd', 'autograd_bwd', 'tidy3d', None]] = tidy3d\n Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.\npost_norm : Union[float, FreqDataArray] = 1.0\n Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.\nmode_spec : ModeSpec\n Container with specifications about the modes to be solved for.\nfreqs : Union[tuple[float, ...], ArrayLike[dtype=float, ndim=1]]\n A list of frequencies at which to solve.\ndirection : Literal['+', '-'] = +\n Direction of waveguide mode propagation along the axis defined by its normal dimension.\ncolocate : bool = True\n Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.\nfields : Tuple[Literal['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz'], ...] = ['Ex', 'Ey', 'Ez', 'Hx', 'Hy', 'Hz']\n Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.\nplane : Union[Box, ModeSource, ModeMonitor, ModeSolverMonitor] = None\n Cross-sectional plane in which the mode will be computed. If provided, the computational domain will be the intersection between the provided ``plane`` and the simulation geometry. If ``None``, the simulation must be 2D, and the plane will be the entire simulation geometry.\n\nThe ``symmetry`` field can be used to enforce reflection symmetry across planes\nthrough the ``center`` of the simulation. Each component of the ``symmetry`` field\nis only used if the ``center`` of the ``plane`` and the simulation geometry\ncoincide in that component. Symmetry normal to the mode solving domain has no\neffect; the field ``filter_pol`` in :class:`.ModeSpec` can be used here instead.\n\nExample\n-------\n>>> from tidy3d import C_0, ModeSpec, BoundarySpec, Boundary\n>>> lambda0 = 1550e-9\n>>> freq0 = C_0 / lambda0\n>>> freqs = [freq0]\n>>> sim_size = lambda0, lambda0, 0\n>>> mode_spec = ModeSpec(num_modes=4)\n>>> boundary_spec = BoundarySpec(\n... x=Boundary.pec(),\n... y=Boundary.pec(),\n... z=Boundary.periodic()\n... )\n>>> sim = ModeSimulation(\n... size=sim_size,\n... freqs=freqs,\n... mode_spec=mode_spec,\n... boundary_spec=boundary_spec\n... )\n\nSee Also\n--------\n\n:class:`ModeSource`:\n Injects current source to excite modal profile on finite extent plane.\n\n**Notebooks:**\n * `Waveguide Y junction <../../notebooks/YJunction.html>`_\n * `Photonic crystal waveguide polarization filter <../../../notebooks/PhotonicCrystalWaveguidePolarizationFilter.html>`_\n\n**Lectures:**\n * `Prelude to Integrated Photonics Simulation: Mode Injection `_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "ModeSimulation", + "enum": [ + "ModeSimulation" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "medium": { + "title": "Background Medium", + "description": "Background medium of simulation, defaults to vacuum if not specified.", + "default": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "discriminator": { + "propertyName": "type", + "mapping": { + "Medium": "#/definitions/Medium", + "AnisotropicMedium": "#/definitions/AnisotropicMedium", + "PECMedium": "#/definitions/PECMedium", + "PMCMedium": "#/definitions/PMCMedium", + "PoleResidue": "#/definitions/PoleResidue", + "Sellmeier": "#/definitions/Sellmeier", + "Lorentz": "#/definitions/Lorentz", + "Debye": "#/definitions/Debye", + "Drude": "#/definitions/Drude", + "FullyAnisotropicMedium": "#/definitions/FullyAnisotropicMedium", + "CustomMedium": "#/definitions/CustomMedium", + "CustomPoleResidue": "#/definitions/CustomPoleResidue", + "CustomSellmeier": "#/definitions/CustomSellmeier", + "CustomLorentz": "#/definitions/CustomLorentz", + "CustomDebye": "#/definitions/CustomDebye", + "CustomDrude": "#/definitions/CustomDrude", + "CustomAnisotropicMedium": "#/definitions/CustomAnisotropicMedium", + "PerturbationMedium": "#/definitions/PerturbationMedium", + "PerturbationPoleResidue": "#/definitions/PerturbationPoleResidue", + "LossyMetalMedium": "#/definitions/LossyMetalMedium" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Medium" + }, + { + "$ref": "#/definitions/AnisotropicMedium" + }, + { + "$ref": "#/definitions/PECMedium" + }, + { + "$ref": "#/definitions/PMCMedium" + }, + { + "$ref": "#/definitions/PoleResidue" + }, + { + "$ref": "#/definitions/Sellmeier" + }, + { + "$ref": "#/definitions/Lorentz" + }, + { + "$ref": "#/definitions/Debye" + }, + { + "$ref": "#/definitions/Drude" + }, + { + "$ref": "#/definitions/FullyAnisotropicMedium" + }, + { + "$ref": "#/definitions/CustomMedium" + }, + { + "$ref": "#/definitions/CustomPoleResidue" + }, + { + "$ref": "#/definitions/CustomSellmeier" + }, + { + "$ref": "#/definitions/CustomLorentz" + }, + { + "$ref": "#/definitions/CustomDebye" + }, + { + "$ref": "#/definitions/CustomDrude" + }, + { + "$ref": "#/definitions/CustomAnisotropicMedium" + }, + { + "$ref": "#/definitions/PerturbationMedium" + }, + { + "$ref": "#/definitions/PerturbationPoleResidue" + }, + { + "$ref": "#/definitions/LossyMetalMedium" + } + ] + }, + "structures": { + "title": "Structures", + "description": "Tuple of structures present in simulation. Note: Structures defined later in this list override the simulation material properties in regions of spatial overlap.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Structure" + } + }, + "symmetry": { + "title": "Symmetries", + "description": "Tuple of integers defining reflection symmetry across a plane bisecting the simulation domain normal to the x-, y-, and z-axis at the simulation center of each axis, respectively. ", + "default": [ + 0, + 0, + 0 + ], + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + }, + { + "enum": [ + 0, + -1, + 1 + ], + "type": "integer" + } + ] + }, + "sources": { + "title": "Sources", + "description": "Sources in the simulation. Note: sources are not supported in mode simulations.", + "default": [], + "type": "array", + "minItems": 0, + "maxItems": 0 + }, + "boundary_spec": { + "title": "Boundaries", + "description": "Specification of boundary conditions along each dimension. If ``None``, PML boundary conditions are applied on all sides. This behavior is for consistency with FDTD simulations; however, please note that the mode solver terminates the mode plane with PEC boundary. The 'ModeSpec' can be used to apply PML layers in the mode solver.", + "default": { + "attrs": {}, + "x": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "y": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "z": { + "attrs": {}, + "plus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "minus": { + "attrs": {}, + "name": null, + "type": "PML", + "num_layers": 12, + "parameters": { + "attrs": {}, + "sigma_order": 3, + "sigma_min": 0.0, + "sigma_max": 1.5, + "type": "PMLParams", + "kappa_order": 3, + "kappa_min": 1.0, + "kappa_max": 3.0, + "alpha_order": 1, + "alpha_min": 0.0, + "alpha_max": 0.0 + } + }, + "type": "Boundary" + }, + "type": "BoundarySpec" + }, + "allOf": [ + { + "$ref": "#/definitions/BoundarySpec" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "Tuple of monitors in the simulation. Note: monitor names are used to access data after simulation is run.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/PermittivityMonitor" + } + }, + "grid_spec": { + "title": "Grid Specification", + "description": "Specifications for the simulation grid along each of the three directions.", + "default": { + "attrs": {}, + "grid_x": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_y": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "grid_z": { + "attrs": {}, + "type": "AutoGrid", + "max_scale": 1.4, + "mesher": { + "attrs": {}, + "type": "GradedMesher" + }, + "dl_min": null, + "min_steps_per_wvl": 10.0, + "min_steps_per_sim_size": 10.0 + }, + "wavelength": null, + "override_structures": [], + "snapping_points": [], + "layer_refinement_specs": [], + "type": "GridSpec" + }, + "allOf": [ + { + "$ref": "#/definitions/GridSpec" + } + ] + }, + "version": { + "title": "Version", + "description": "String specifying the front end version number.", + "default": "2.9.0", + "type": "string" + }, + "plot_length_units": { + "title": "Plot Units", + "description": "When set to a supported ``LengthUnit``, plots will be produced with proper scaling of axes and include the desired unit specifier in labels.", + "default": "\u03bcm", + "enum": [ + "nm", + "\u03bcm", + "um", + "mm", + "cm", + "m" + ], + "type": "string" + }, + "structure_priority_mode": { + "title": "Structure Priority Setting", + "description": "This field only affects structures of `priority=None`. If `equal`, the priority of those structures is set to 0; if `conductor`, the priority of structures made of `LossyMetalMedium` is set to 90, `PECMedium` to 100, and others to 0.", + "default": "equal", + "enum": [ + "equal", + "conductor" + ], + "type": "string" + }, + "lumped_elements": { + "title": "Lumped Elements", + "description": "Tuple of lumped elements in the simulation. Note: only :class:`tidy3d.LumpedResistor` is supported currently.", + "default": [], + "type": "array", + "items": { + "discriminator": { + "propertyName": "type", + "mapping": { + "LumpedResistor": "#/definitions/LumpedResistor", + "CoaxialLumpedResistor": "#/definitions/CoaxialLumpedResistor", + "LinearLumpedElement": "#/definitions/LinearLumpedElement" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/LumpedResistor" + }, + { + "$ref": "#/definitions/CoaxialLumpedResistor" + }, + { + "$ref": "#/definitions/LinearLumpedElement" + } + ] + } + }, + "subpixel": { + "title": "Subpixel Averaging", + "description": "Apply subpixel averaging methods of the permittivity on structure interfaces to result in much higher accuracy for a given grid size. Supply a :class:`SubpixelSpec` to this field to select subpixel averaging methods separately on dielectric, metal, and PEC material interfaces. Alternatively, user may supply a boolean value: ``True`` to apply the default subpixel averaging methods corresponding to ``SubpixelSpec()`` , or ``False`` to apply staircasing.", + "default": { + "attrs": {}, + "dielectric": { + "attrs": {}, + "type": "PolarizedAveraging" + }, + "metal": { + "attrs": {}, + "type": "Staircasing" + }, + "pec": { + "attrs": {}, + "type": "PECConformal", + "timestep_reduction": 0.3, + "edge_singularity_correction": false + }, + "pmc": { + "attrs": {}, + "type": "Staircasing" + }, + "lossy_metal": { + "attrs": {}, + "type": "SurfaceImpedance", + "timestep_reduction": 0.0, + "edge_singularity_correction": false + }, + "type": "SubpixelSpec" + }, + "anyOf": [ + { + "type": "boolean" + }, + { + "$ref": "#/definitions/SubpixelSpec" + } + ] + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Tag used internally to distinguish types of simulations for ``autograd`` gradient processing.", + "default": "tidy3d", + "enum": [ + "autograd_fwd", + "autograd_bwd", + "tidy3d" + ], + "type": "string" + }, + "post_norm": { + "title": "Post Normalization Values", + "description": "Factor to multiply the fields by after running, given the adjoint source pipeline used. Note: this is used internally only.", + "default": 1.0, + "anyOf": [ + { + "type": "number" + }, + { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]" + } + }, + "required": [ + "_dims" + ] + } + ] + }, + "mode_spec": { + "title": "Mode specification", + "description": "Container with specifications about the modes to be solved for.", + "allOf": [ + { + "$ref": "#/definitions/ModeSpec" + } + ] + }, + "freqs": { + "title": "Frequencies", + "description": "A list of frequencies at which to solve.", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "ArrayLike" + } + ] + }, + "direction": { + "title": "Propagation direction", + "description": "Direction of waveguide mode propagation along the axis defined by its normal dimension.", + "default": "+", + "enum": [ + "+", + "-" + ], + "type": "string" + }, + "colocate": { + "title": "Colocate fields", + "description": "Toggle whether fields should be colocated to grid cell boundaries (i.e. primal grid nodes). Default is ``True``.", + "default": true, + "type": "boolean" + }, + "fields": { + "title": "Field Components", + "description": "Collection of field components to store in the monitor. Note that some methods like ``flux``, ``dot`` require all tangential field components, while others like ``mode_area`` require all E-field components.", + "default": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "array", + "items": { + "enum": [ + "Ex", + "Ey", + "Ez", + "Hx", + "Hy", + "Hz" + ], + "type": "string" + } + }, + "plane": { + "title": "Plane", + "description": "Cross-sectional plane in which the mode will be computed. If provided, the computational domain will be the intersection between the provided ``plane`` and the simulation geometry. If ``None``, the simulation must be 2D, and the plane will be the entire simulation geometry.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Box": "#/definitions/Box", + "ModeSource": "#/definitions/ModeSource", + "ModeMonitor": "#/definitions/ModeMonitor", + "ModeSolverMonitor": "#/definitions/ModeSolverMonitor" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Box" + }, + { + "$ref": "#/definitions/ModeSource" + }, + { + "$ref": "#/definitions/ModeMonitor" + }, + { + "$ref": "#/definitions/ModeSolverMonitor" + } + ] + } + }, + "required": [ + "size", + "mode_spec", + "freqs" + ], + "additionalProperties": false + }, + "VolumeMeshMonitor": { + "title": "VolumeMeshMonitor", + "description": "Monitor recording the volume mesh. The monitor size must be either 2D or 3D. If a 2D monitor\nis used in a 3D simulation, the sliced volumetric mesh on the plane of the monitor will be\nstored as a ``TriangularGridDataset``.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\ncenter : Union[tuple[Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box], Union[float, autograd.tracer.Box]], Box] = (0.0, 0.0, 0.0)\n [units = um]. Center of object in x, y, and z.\nsize : Union[tuple[Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box], Union[pydantic.v1.types.NonNegativeFloat, autograd.tracer.Box]], Box]\n [units = um]. Size in x, y, and z directions.\nname : ConstrainedStrValue\n Unique name for monitor.\nunstructured : Literal[True] = True\n Return the original unstructured grid.\nconformal : bool = False\n If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "VolumeMeshMonitor", + "enum": [ + "VolumeMeshMonitor" + ], + "type": "string" + }, + "center": { + "title": "Center", + "description": "Center of object in x, y, and z.", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number" + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "size": { + "title": "Size", + "description": "Size in x, y, and z directions.", + "units": "um", + "anyOf": [ + { + "type": "array", + "minItems": 3, + "maxItems": 3, + "items": [ + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "minimum": 0 + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + } + ] + }, + { + "title": "AutogradBox", + "type": "autograd.tracer.Box" + } + ] + }, + "name": { + "title": "Name", + "description": "Unique name for monitor.", + "minLength": 1, + "type": "string" + }, + "unstructured": { + "title": "Unstructured Grid", + "description": "Return the original unstructured grid.", + "default": true, + "enum": [ + true + ], + "type": "boolean" + }, + "conformal": { + "title": "Conformal Monitor Meshing", + "description": "If ``True`` the simulation mesh will conform to the monitor's geometry. While this can be set for both Cartesian and unstructured monitors, it bears higher significance for the latter ones. Effectively, setting ``conformal = True`` for unstructured monitors (``unstructured = True``) ensures that returned values will not be obtained by interpolation during postprocessing but rather directly transferred from the computational grid.", + "default": false, + "type": "boolean" + } + }, + "required": [ + "size", + "name" + ], + "additionalProperties": false + }, + "VolumeMesher": { + "title": "VolumeMesher", + "description": "Specification for a standalone volume mesher.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsimulation : HeatChargeSimulation\n HeatCharge simulation instance for the mesh specification.\nmonitors : Tuple[VolumeMeshMonitor, ...] = ()\n List of monitors to be used for the mesher.", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "simulation": { + "title": "Simulation", + "description": "HeatCharge simulation instance for the mesh specification.", + "allOf": [ + { + "$ref": "#/definitions/HeatChargeSimulation" + } + ] + }, + "monitors": { + "title": "Monitors", + "description": "List of monitors to be used for the mesher.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/VolumeMeshMonitor" + } + }, + "type": { + "title": "Type", + "default": "VolumeMesher", + "enum": [ + "VolumeMesher" + ], + "type": "string" + } + }, + "required": [ + "simulation" + ], + "additionalProperties": false + }, + "PayType": { + "title": "PayType", + "description": "An enumeration.", + "enum": [ + "FLEX_CREDIT", + "AUTO" + ], + "type": "string" + }, + "Job": { + "title": "Job", + "description": "Interface for managing the running of a :class:`.Simulation` on server.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsimulation : Union[Simulation, HeatChargeSimulation, HeatSimulation, EMESimulation, ModeSolver, ModeSimulation, VolumeMesher]\n Simulation to run as a 'task'.\ntask_name : str\n Unique name of the task.\nfolder_name : str = default\n Name of folder to store task on web UI.\ncallback_url : Optional[str] = None\n Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.\nsolver_version : Optional[str] = None\n Custom solver version to use, otherwise uses default for the current front end version.\nverbose : bool = True\n Whether to print info messages and progressbars.\nsimulation_type : str = tidy3d\n Type of simulation, used internally only.\nparent_tasks : Optional[Tuple[str, ...]] = None\n Tuple of parent task ids, used internally only.\ntask_id_cached : Optional[str] = None\n Optional field to specify ``task_id``. Only used as a workaround internally so that ``task_id`` is written when ``Job.to_file()`` and then the proper task is loaded from ``Job.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.\nreduce_simulation : Literal['auto', True, False] = auto\n Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver.\npay_type : PayType = PayType.AUTO\n Specify the payment method.\n\nNotes\n-----\n\n This class provides a more convenient way to manage single simulations, mainly because it eliminates the need\n for keeping track of the ``task_id`` and original :class:`.Simulation`.\n\n We can get the cost estimate of running the task before actually running it. This prevents us from\n accidentally running large jobs that we set up by mistake. The estimated cost is the maximum cost\n corresponding to running all the time steps.\n\n Another convenient thing about :class:`Job` objects is that they can be saved and loaded just like other\n ``tidy3d`` components.\n\nExamples\n--------\n\n Once you've created a ``job`` object using :class:`tidy3d.web.api.container.Job`, you can upload it to our servers with:\n\n .. code-block:: python\n\n tidy3d.web.upload(simulation, task_name=\"task_name\", verbose=verbose)`\n\n It will not run until you explicitly tell it to do so with:\n\n .. code-block:: python\n\n tidy3d.web.api.webapi.start(job.task_id)\n\n To monitor the simulation's progress and wait for its completion, use\n\n .. code-block:: python\n\n tidy3d.web.api.webapi.monitor(job.task_id, verbose=verbose)\n\n After running the simulation, you can load the results using for example:\n\n .. code-block:: python\n\n sim_data = tidy3d.web.api.webapi.load(job.task_id, path=\"out/simulation.hdf5\", verbose=verbose)\n\n The job container has a convenient method to save and load the results of a job that has already finished,\n without needing to know the task_id, as below:\n\n .. code-block:: python\n\n # Saves the job metadata to a single file.\n job.to_file(\"data/job.json\")\n\n # You can exit the session, break here, or continue in new session.\n\n # Load the job metadata from file.\n job_loaded = tidy3d.web.api.container.Job.from_file(\"data/job.json\")\n\n # Download the data from the server and load it into a SimulationData object.\n sim_data = job_loaded.load(path=\"data/sim.hdf5\")\n\n\nSee Also\n--------\n\n:meth:`tidy3d.web.api.webapi.run_async`\n Submits a set of :class:`.Simulation` objects to server, starts running, monitors progress,\n downloads, and loads results as a :class:`.BatchData` object.\n\n:class:`Batch`\n Interface for submitting several :class:`Simulation` objects to sever.\n\n**Notebooks**\n * `Running simulations through the cloud <../../notebooks/WebAPI.html>`_\n * `Performing parallel / batch processing of simulations <../../notebooks/ParameterScan.html>`_\n * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Job", + "enum": [ + "Job" + ], + "type": "string" + }, + "simulation": { + "title": "simulation", + "description": "Simulation to run as a 'task'.", + "discriminator": { + "propertyName": "type", + "mapping": { + "Simulation": "#/definitions/Simulation", + "HeatChargeSimulation": "#/definitions/HeatChargeSimulation", + "HeatSimulation": "#/definitions/HeatSimulation", + "EMESimulation": "#/definitions/EMESimulation", + "ModeSolver": "#/definitions/ModeSolver", + "ModeSimulation": "#/definitions/ModeSimulation", + "VolumeMesher": "#/definitions/VolumeMesher" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Simulation" + }, + { + "$ref": "#/definitions/HeatChargeSimulation" + }, + { + "$ref": "#/definitions/HeatSimulation" + }, + { + "$ref": "#/definitions/EMESimulation" + }, + { + "$ref": "#/definitions/ModeSolver" + }, + { + "$ref": "#/definitions/ModeSimulation" + }, + { + "$ref": "#/definitions/VolumeMesher" + } + ] + }, + "task_name": { + "title": "Task Name", + "description": "Unique name of the task.", + "type": "string" + }, + "folder_name": { + "title": "Folder Name", + "description": "Name of folder to store task on web UI.", + "default": "default", + "type": "string" + }, + "callback_url": { + "title": "Callback URL", + "description": "Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.", + "type": "string" + }, + "solver_version": { + "title": "Solver Version", + "description": "Custom solver version to use, otherwise uses default for the current front end version.", + "type": "string" + }, + "verbose": { + "title": "Verbose", + "description": "Whether to print info messages and progressbars.", + "default": true, + "type": "boolean" + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Type of simulation, used internally only.", + "default": "tidy3d", + "type": "string" + }, + "parent_tasks": { + "title": "Parent Tasks", + "description": "Tuple of parent task ids, used internally only.", + "type": "array", + "items": { + "type": "string" + } + }, + "task_id_cached": { + "title": "Task ID (Cached)", + "description": "Optional field to specify ``task_id``. Only used as a workaround internally so that ``task_id`` is written when ``Job.to_file()`` and then the proper task is loaded from ``Job.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.", + "type": "string" + }, + "reduce_simulation": { + "title": "Reduce Simulation", + "description": "Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver.", + "default": "auto", + "anyOf": [ + { + "enum": [ + "auto" + ], + "type": "string" + }, + { + "enum": [ + true, + false + ], + "type": "boolean" + } + ] + }, + "pay_type": { + "title": "Payment Type", + "description": "Specify the payment method.", + "default": "AUTO", + "allOf": [ + { + "$ref": "#/definitions/PayType" + } + ] + } + }, + "required": [ + "simulation", + "task_name" + ], + "additionalProperties": false + }, + "Batch": { + "title": "Batch", + "description": "Interface for submitting several :class:`Simulation` objects to sever.\n\nParameters\n----------\nattrs : dict = {}\n Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.\nsimulations : Mapping[str, Annotated[Union[tidy3d.components.simulation.Simulation, tidy3d.components.tcad.simulation.heat_charge.HeatChargeSimulation, tidy3d.components.tcad.simulation.heat.HeatSimulation, tidy3d.components.eme.simulation.EMESimulation, tidy3d.components.mode.mode_solver.ModeSolver, tidy3d.components.mode.simulation.ModeSimulation, tidy3d.components.tcad.mesher.VolumeMesher], FieldInfo(default=PydanticUndefined, discriminator='type', extra={})]]\n Mapping of task names to Simulations to run as a batch.\nfolder_name : str = default\n Name of folder to store member of each batch on web UI.\nverbose : bool = True\n Whether to print info messages and progressbars.\nsolver_version : Optional[str] = None\n Custom solver version to use, otherwise uses default for the current front end version.\ncallback_url : Optional[str] = None\n Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.\nsimulation_type : str = tidy3d\n Type of each simulation in the batch, used internally only.\nparent_tasks : Optional[Mapping[str, tuple[str, ...]]] = None\n Collection of parent task ids for each job in batch, used internally only.\nnum_workers : Optional[PositiveInt] = 10\n Number of workers for multi-threading upload and download of batch. Corresponds to ``max_workers`` argument passed to ``concurrent.futures.ThreadPoolExecutor``. When left ``None``, will pass the maximum number of threads available on the system.\nreduce_simulation : Literal['auto', True, False] = auto\n Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver.\npay_type : PayType = PayType.AUTO\n Specify the payment method.\njobs_cached : Optional[Mapping[str, Job]] = None\n Optional field to specify ``jobs``. Only used as a workaround internally so that ``jobs`` is written when ``Batch.to_file()`` and then the proper task is loaded from ``Batch.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.\n\nNotes\n-----\n\n Commonly one needs to submit a batch of :class:`Simulation`. The built-in :class:`Batch` object is the best way to upload,\n start, monitor, and load a series of tasks. The batch object is like a :class:`Job`, but stores task metadata\n for a series of simulations.\n\nSee Also\n--------\n\n:meth:`tidy3d.web.api.webapi.run_async`\n Submits a set of :class:`.Simulation` objects to server, starts running, monitors progress,\n downloads, and loads results as a :class:`.BatchData` object.\n\n:class:`Job`:\n Interface for managing the running of a Simulation on server.\n\n**Notebooks**\n * `Running simulations through the cloud <../../notebooks/WebAPI.html>`_\n * `Performing parallel / batch processing of simulations <../../notebooks/ParameterScan.html>`_\n * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_", + "type": "object", + "properties": { + "attrs": { + "title": "Attributes", + "description": "Dictionary storing arbitrary metadata for a Tidy3D object. This dictionary can be freely used by the user for storing data without affecting the operation of Tidy3D as it is not used internally. Note that, unlike regular Tidy3D fields, ``attrs`` are mutable. For example, the following is allowed for setting an ``attr`` ``obj.attrs['foo'] = bar``. Also note that `Tidy3D`` will raise a ``TypeError`` if ``attrs`` contain objects that can not be serialized. One can check if ``attrs`` are serializable by calling ``obj.json()``.", + "default": {}, + "type": "object" + }, + "type": { + "title": "Type", + "default": "Batch", + "enum": [ + "Batch" + ], + "type": "string" + }, + "simulations": { + "title": "Simulations", + "description": "Mapping of task names to Simulations to run as a batch.", + "type": "object", + "additionalProperties": { + "discriminator": { + "propertyName": "type", + "mapping": { + "Simulation": "#/definitions/Simulation", + "HeatChargeSimulation": "#/definitions/HeatChargeSimulation", + "HeatSimulation": "#/definitions/HeatSimulation", + "EMESimulation": "#/definitions/EMESimulation", + "ModeSolver": "#/definitions/ModeSolver", + "ModeSimulation": "#/definitions/ModeSimulation", + "VolumeMesher": "#/definitions/VolumeMesher" + } + }, + "oneOf": [ + { + "$ref": "#/definitions/Simulation" + }, + { + "$ref": "#/definitions/HeatChargeSimulation" + }, + { + "$ref": "#/definitions/HeatSimulation" + }, + { + "$ref": "#/definitions/EMESimulation" + }, + { + "$ref": "#/definitions/ModeSolver" + }, + { + "$ref": "#/definitions/ModeSimulation" + }, + { + "$ref": "#/definitions/VolumeMesher" + } + ] + } + }, + "folder_name": { + "title": "Folder Name", + "description": "Name of folder to store member of each batch on web UI.", + "default": "default", + "type": "string" + }, + "verbose": { + "title": "Verbose", + "description": "Whether to print info messages and progressbars.", + "default": true, + "type": "boolean" + }, + "solver_version": { + "title": "Solver Version", + "description": "Custom solver version to use, otherwise uses default for the current front end version.", + "type": "string" + }, + "callback_url": { + "title": "Callback URL", + "description": "Http PUT url to receive simulation finish event. The body content is a json file with fields ``{'id', 'status', 'name', 'workUnit', 'solverVersion'}``.", + "type": "string" + }, + "simulation_type": { + "title": "Simulation Type", + "description": "Type of each simulation in the batch, used internally only.", + "default": "tidy3d", + "type": "string" + }, + "parent_tasks": { + "title": "Parent Tasks", + "description": "Collection of parent task ids for each job in batch, used internally only.", + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "num_workers": { + "title": "Number of Workers", + "description": "Number of workers for multi-threading upload and download of batch. Corresponds to ``max_workers`` argument passed to ``concurrent.futures.ThreadPoolExecutor``. When left ``None``, will pass the maximum number of threads available on the system.", + "default": 10, + "exclusiveMinimum": 0, + "type": "integer" + }, + "reduce_simulation": { + "title": "Reduce Simulation", + "description": "Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver.", + "default": "auto", + "anyOf": [ + { + "enum": [ + "auto" + ], + "type": "string" + }, + { + "enum": [ + true, + false + ], + "type": "boolean" + } + ] + }, + "pay_type": { + "title": "Payment Type", + "description": "Specify the payment method.", + "default": "AUTO", + "allOf": [ + { + "$ref": "#/definitions/PayType" + } + ] + }, + "jobs_cached": { + "title": "Jobs (Cached)", + "description": "Optional field to specify ``jobs``. Only used as a workaround internally so that ``jobs`` is written when ``Batch.to_file()`` and then the proper task is loaded from ``Batch.from_file()``. We recommend leaving unset as setting this field along with fields that were not used to create the task will cause errors.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Job" + } + } + }, + "required": [ + "simulations" + ], + "additionalProperties": false + } + } +} \ No newline at end of file diff --git a/scripts/benchmark_import.py b/scripts/benchmark_import.py index beb304096f..cb430999d8 100644 --- a/scripts/benchmark_import.py +++ b/scripts/benchmark_import.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + def test_import(): import subprocess import time diff --git a/scripts/make_script.py b/scripts/make_script.py index aeacbf5c40..cbd061f095 100644 --- a/scripts/make_script.py +++ b/scripts/make_script.py @@ -8,6 +8,8 @@ """ +from __future__ import annotations + import argparse import os import re @@ -83,11 +85,11 @@ def main(args): # read the formatted content back with open(temp_file_path, encoding="utf-8") as temp_file: sim_string = temp_file.read() - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as exc: raise RuntimeError( "Ruff formatting failed. Your script might not be compatible with make_script.py. " "This could be due to unsupported features like CustomMedium." - ) + ) from exc finally: # remove the temporary file os.remove(temp_file_path) diff --git a/scripts/pre_release.sh b/scripts/pre_release.sh index 8f81b195cb..3246a9d92e 100644 --- a/scripts/pre_release.sh +++ b/scripts/pre_release.sh @@ -1,5 +1,4 @@ #!/bin/bash set -e -python scripts/schema.py -python scripts/sample.py \ No newline at end of file +python scripts/sample.py diff --git a/scripts/regenerate_schema.py b/scripts/regenerate_schema.py new file mode 100644 index 0000000000..29be331f23 --- /dev/null +++ b/scripts/regenerate_schema.py @@ -0,0 +1,95 @@ +""" +Generates and saves JSON schemas for key tidy3d data structures. + +This script iterates through a predefined dictionary of Tidy3D classes, +generates a Pydantic JSON schema for each, and saves it as a formatted +JSON file in the 'schemas' directory. It's designed to be run as a +standalone utility to update schema definitions. + +All are GUI supported classes. +""" + +from __future__ import annotations + +import json +import pathlib +import sys + +# Attempt to import necessary classes from tidy3d. +try: + from tidy3d import ( + EMESimulation, + HeatChargeSimulation, + HeatSimulation, + ModeSimulation, + Simulation, + ) + from tidy3d.plugins.smatrix import TerminalComponentModeler +except ImportError as e: + print( + f"Error: Failed to import from 'tidy3d'. Ensure it's installed. Details: {e}", + file=sys.stderr, + ) + sys.exit(1) + + +# Define the output directory relative to this script's location. +# Assumes the script is in a subdirectory like 'scripts' and 'schemas' is a sibling. +SCHEMA_DIR = pathlib.Path(__file__).parent.parent / "schemas" + +# Dictionary mapping a clean name to the Pydantic model class. +# This is the single source of truth for which schemas to export. +export_api_schema_dictionary = { + "Simulation": Simulation, + "ModeSimulation": ModeSimulation, + "EMESimulation": EMESimulation, + "HeatSimulation": HeatSimulation, + "HeatChargeSimulation": HeatChargeSimulation, + "TerminalComponentModeler": TerminalComponentModeler, +} + + +def generate_schemas(): + """ + Generates and saves a JSON schema for each class in the global dictionary. + + This function handles the creation of the output directory and iterates + through each item in `export_api_schema_dictionary`. For each item, it + generates the schema and writes it to a corresponding '.json' file. + It includes error handling for file system operations. + + Raises: + OSError: If there is an issue creating the directory or writing files, + such as a permissions error. + """ + try: + # Create the output directory if it doesn't exist. + SCHEMA_DIR.mkdir(parents=True, exist_ok=True) + print(f"Saving schemas to '{SCHEMA_DIR}/'") + + for name, class_instance in export_api_schema_dictionary.items(): + output_path = SCHEMA_DIR / f"{name}.json" + print(f" -> Generating schema for '{name}'...") + + # Generate the schema dictionary from the class. + schema_dict = class_instance.schema() + + # Write the schema to a file with pretty printing. + with open(output_path, "w") as f: + json.dump(schema_dict, f, indent=2) + + except OSError as e: + print( + "\nError: A file system error occurred. Check permissions and paths.", file=sys.stderr + ) + print(f"Details: {e}", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"\nAn unexpected error occurred: {e}", file=sys.stderr) + sys.exit(1) + + print("\nSchema generation complete. ✨") + + +if __name__ == "__main__": + generate_schemas() diff --git a/scripts/sample.py b/scripts/sample.py index 2e679a9fe6..a559d5fb15 100644 --- a/scripts/sample.py +++ b/scripts/sample.py @@ -1,14 +1,17 @@ """Generates sample simulation json and h5 files in the tests/sims folder""" +from __future__ import annotations + import sys from os.path import join sys.path.append("tests") -from utils import SIM_FULL +from utils import SAMPLE_SIMULATIONS -FPREFIX_SIMULATION_SAMPLE = join("tests", "sims", "simulation_sample") +FPREFIX_SIMULATION_SAMPLE = join("tests", "sims") -# Store a simulation sample as json and hdf5 -SIM_FULL.to_json(FPREFIX_SIMULATION_SAMPLE + ".json") -SIM_FULL.to_hdf5(FPREFIX_SIMULATION_SAMPLE + ".h5") +for key, sim in SAMPLE_SIMULATIONS.items(): + # Store a simulation sample as json and hdf5 + sim.to_json(join(FPREFIX_SIMULATION_SAMPLE, key) + ".json") + sim.to_hdf5(join(FPREFIX_SIMULATION_SAMPLE, key) + ".h5") diff --git a/scripts/schema.py b/scripts/schema.py deleted file mode 100644 index b3e5fa962f..0000000000 --- a/scripts/schema.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Generates schema for Simulation, saves it to file.""" - -import json - -import tidy3d - -FNAME = "tidy3d/schema.json" - -# https://pydantic-docs.helpmanual.io/usage/schema/ -schema_dict = tidy3d.Simulation.schema() -with open(FNAME, "w") as f: - json.dump(schema_dict, f, indent=2) diff --git a/scripts/test_local.sh b/scripts/test_coverage.sh similarity index 51% rename from scripts/test_local.sh rename to scripts/test_coverage.sh index 152ddf247a..43ff2e5671 100755 --- a/scripts/test_local.sh +++ b/scripts/test_coverage.sh @@ -1,13 +1,9 @@ #!/bin/bash set -e -ruff format tidy3d/ --check --diff -ruff format tests/ --check --diff -ruff format scripts/ --check --diff - -ruff check tidy3d --diff - -pytest -rA tests/ +pytest -rA --cov tests/ # to test without vtk, one has to restart pytest pytest -rA tests/_test_data/_test_datasets_no_vtk.py pytest --doctest-modules tidy3d/ docs/ +coverage xml +diff-cover --compare-branch=origin/develop coverage.xml diff --git a/scripts/test_format.sh b/scripts/test_format.sh new file mode 100755 index 0000000000..abbd300470 --- /dev/null +++ b/scripts/test_format.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +ruff format tidy3d/ --check --diff +ruff format tests/ --check --diff +ruff format scripts/ --check --diff + +ruff check tidy3d --diff diff --git a/tests/__init__.py b/tests/__init__.py index 5f4adad8e9..0bee19ee71 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import sys sys.path.append("./") diff --git a/tests/_test_data/_test_datasets_no_vtk.py b/tests/_test_data/_test_datasets_no_vtk.py index 227c4a29c3..0e6866ac65 100644 --- a/tests/_test_data/_test_datasets_no_vtk.py +++ b/tests/_test_data/_test_datasets_no_vtk.py @@ -1,5 +1,7 @@ """Tests tidy3d/components/data/dataset.py""" +from __future__ import annotations + import builtins import pytest @@ -14,7 +16,7 @@ def hide_vtk(monkeypatch, request): def mocked_import(name, *args, **kwargs): if name in ["vtk", "vtkmodules.vtkCommonCore"]: - raise ImportError() + raise ImportError return import_orig(name, *args, **kwargs) monkeypatch.setattr(builtins, "__import__", mocked_import) diff --git a/tests/_test_local/_test_adjoint_performance.py b/tests/_test_local/_test_adjoint_performance.py index 616065460c..dfe9c18bf7 100644 --- a/tests/_test_local/_test_adjoint_performance.py +++ b/tests/_test_local/_test_adjoint_performance.py @@ -1,12 +1,15 @@ +from __future__ import annotations + import sys import time import matplotlib.pyplot as plt import numpy as np import pytest -import tidy3d as td from jax import grad from memory_profiler import profile + +import tidy3d as td from tidy3d.plugins.adjoint.components.data.data_array import JaxDataArray from tidy3d.plugins.adjoint.components.data.dataset import JaxPermittivityDataset from tidy3d.plugins.adjoint.components.geometry import JaxBox @@ -52,12 +55,12 @@ def make_sim(eps_values: np.ndarray) -> JaxSimulation: # custom medium (xmin, ymin, zmin), (xmax, ymax, zmax) = jax_box.bounds - coords = dict( - x=np.linspace(xmin, xmax, Nx).tolist(), - y=np.linspace(ymin, ymax, Ny).tolist(), - z=np.linspace(zmin, zmax, Nz).tolist(), - f=[FREQ0], - ) + coords = { + "x": np.linspace(xmin, xmax, Nx).tolist(), + "y": np.linspace(ymin, ymax, Ny).tolist(), + "z": np.linspace(zmin, zmax, Nz).tolist(), + "f": [FREQ0], + } eps_ii = JaxDataArray(values=eps_values, coords=coords) field_components = {f"eps_{dim}{dim}": eps_ii for dim in "xyz"} diff --git a/tests/_test_local/_test_adjoint_performance_multi.py b/tests/_test_local/_test_adjoint_performance_multi.py index 1ea12222e3..3b2ebc3f63 100644 --- a/tests/_test_local/_test_adjoint_performance_multi.py +++ b/tests/_test_local/_test_adjoint_performance_multi.py @@ -1,11 +1,14 @@ +from __future__ import annotations + import cProfile import jax import jax.numpy as jnp import pytest +from memory_profiler import profile + import tidy3d as td import tidy3d.plugins.adjoint as tda -from memory_profiler import profile from tidy3d.plugins.adjoint.web import run_local as run from ..utils import run_emulated diff --git a/tests/_test_local/_test_data_performance.py b/tests/_test_local/_test_data_performance.py index ceb272fabc..a4b86c668f 100644 --- a/tests/_test_local/_test_data_performance.py +++ b/tests/_test_local/_test_data_performance.py @@ -1,9 +1,12 @@ +from __future__ import annotations + import os import sys import numpy as np -import tidy3d as td from memory_profiler import profile + +import tidy3d as td from tidy3d.components.data.data_array import ScalarFieldDataArray from tidy3d.components.data.monitor_data import FieldData from tidy3d.components.data.sim_data import SimulationData @@ -48,7 +51,7 @@ def make_sim_data_1(file_size_gb=FILE_SIZE_GB): src = PointDipole( center=(0, 0, 0), source_time=GaussianPulse(freq0=3e14, fwidth=1e14), polarization="Ex" ) - coords = dict(x=x, y=y, z=z, f=f) + coords = {"x": x, "y": y, "z": z, "f": f} Ex = ScalarFieldDataArray(data, coords=coords) monitor = FieldMonitor(size=(2, 2, 2), freqs=f, name="test", fields=["Ex"]) field_data = FieldData(monitor=monitor, Ex=Ex) @@ -70,7 +73,7 @@ def make_sim_data_1(file_size_gb=FILE_SIZE_GB): @profile def test_memory_1_save(): - print(f'sim_data_size = {SIM_DATA_1.monitor_data["test"].Ex.nbytes:.2e} Bytes') + print(f"sim_data_size = {SIM_DATA_1.monitor_data['test'].Ex.nbytes:.2e} Bytes") SIM_DATA_1.to_file(PATH) print(f"file_size = {os.path.getsize(PATH):.2e} Bytes") @@ -88,7 +91,7 @@ def test_core_profile_small_1_save(): y = np.arange(Ny) z = np.arange(Nz) t = np.arange(Nt) - coords = dict(x=x, y=y, z=z, t=t) + coords = {"x": x, "y": y, "z": z, "t": t} scalar_field = td.ScalarFieldTimeDataArray(np.random.random((Nx, Ny, Nz, Nt)), coords=coords) monitor = td.FieldTimeMonitor(size=(2, 4, 6), interval=100, name="field", fields=["Ex", "Hz"]) data = td.FieldTimeData(monitor=monitor, Ex=scalar_field, Hz=scalar_field) @@ -123,7 +126,7 @@ def test_speed_many_datasets(): y = np.arange(Ny) z = np.arange(Nz) f = np.arange(Nf) - coords = dict(x=x, y=y, z=z, f=f) + coords = {"x": x, "y": y, "z": z, "f": f} scalar_field = td.ScalarFieldDataArray(np.random.random((Nx, Ny, Nz, Nf)), coords=coords) def make_field_data(num_index: int): @@ -133,7 +136,7 @@ def make_field_data(num_index: int): freqs=np.linspace(1e14, 2e14, Nf).tolist(), name=str(num_index), ) - scalar_fields = {fld: scalar_field for fld in monitor.fields} + scalar_fields = dict.fromkeys(monitor.fields, scalar_field) return td.FieldData(monitor=monitor, **scalar_fields) diff --git a/tests/_test_local/_test_fit_web.py b/tests/_test_local/_test_fit_web.py index 92c06b7963..b135514017 100644 --- a/tests/_test_local/_test_fit_web.py +++ b/tests/_test_local/_test_fit_web.py @@ -1,6 +1,9 @@ +from __future__ import annotations + from math import isclose import numpy as np + from tidy3d.plugins.fitter import AdvancedFitterParam, StableDispersionFitter np.random.seed(4) diff --git a/tests/_test_local/_test_plugins_web.py b/tests/_test_local/_test_plugins_web.py index cbf9b2d4ce..a475889cff 100644 --- a/tests/_test_local/_test_plugins_web.py +++ b/tests/_test_local/_test_plugins_web.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import numpy as np + from tidy3d.plugins.fitter import DispersionFitter, StableDispersionFitter diff --git a/tests/_test_local/_test_web.py b/tests/_test_local/_test_web.py index 75c93f61ca..5662a27853 100644 --- a/tests/_test_local/_test_web.py +++ b/tests/_test_local/_test_web.py @@ -1,5 +1,7 @@ """tests converted webapi""" +from __future__ import annotations + import os from unittest import TestCase, mock diff --git a/tests/_test_notebooks/full_test_notebooks.py b/tests/_test_notebooks/full_test_notebooks.py index 22eca50834..da8fbe0158 100644 --- a/tests/_test_notebooks/full_test_notebooks.py +++ b/tests/_test_notebooks/full_test_notebooks.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys @@ -66,7 +68,7 @@ ] # if any run only supplied, only add those -if len(run_only): +if run_only: notebook_filenames_all = [NOTEBOOK_DIR + base + ".ipynb" for base in run_only] # filter out the skip notebooks diff --git a/tests/conftest.py b/tests/conftest.py index a1c37d57d8..165303e944 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os from pathlib import Path @@ -7,9 +9,11 @@ import numpy as np import psutil import pytest -import tidy3d as td from autograd.test_util import check_grads from autograd.wrap_util import unary_to_nary + +import tidy3d as td +from tidy3d.config import config from tidy3d.log import DEFAULT_LEVEL, set_logging_console, set_logging_level @@ -68,6 +72,9 @@ def pytest_xdist_auto_num_workers(config): cores = min(cores, mem_limited_cores) if os.getenv("GITHUB_ACTIONS"): + if os.getenv("RUNNER_ENVIRONMENT") == "self-hosted": + MAX_SELF_HOSTED_CORES = 8 + return min(MAX_SELF_HOSTED_CORES, cores) return cores return max(1, cores - 1) @@ -91,6 +98,15 @@ def mpl_config_interactive(): mpl.use(original_backend) +@pytest.fixture(autouse=True) +def disable_local_subpixel(): + """Disable local subpixel for the unit tests.""" + use_local_subpixel = config.use_local_subpixel + config.use_local_subpixel = False + yield + config.use_local_subpixel = use_local_subpixel + + @pytest.fixture def dir_name(request): return request.param diff --git a/tests/data/gmsh.vtk b/tests/data/gmsh.vtk new file mode 100644 index 0000000000..32c4bc35eb --- /dev/null +++ b/tests/data/gmsh.vtk @@ -0,0 +1,23013 @@ +# vtk DataFile Version 2.0 +model, Created by Gmsh 4.13.1 +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 1382 double +0.2 -0.05 -0.05 +0.2 -0.05 0.05 +0.2 0.05 -0.05 +0.2 0.05 0.05 +0.5 -0.05 -0.05 +0.5 -0.05 0.05 +0.5 0.05 -0.05 +0.5 0.05 0.05 +0.8999999999999999 -0.05 -0.05 +0.8999999999999999 -0.05 0.05 +0.8999999999999999 0.05 -0.05 +0.8999999999999999 0.05 0.05 +0.2 -0.05 0.03000000000000001 +0.2 -0.05 0.009999999999999974 +0.2 -0.05 -0.01 +0.2 -0.05 -0.03000000000000001 +0.2 -0.02999999999999997 -0.05 +0.2 -0.009999999999999933 -0.05 +0.2 0.01000000000000008 -0.05 +0.2 0.03000000000000007 -0.05 +0.2 -0.02999999999999997 0.05 +0.2 -0.009999999999999933 0.05 +0.2 0.01000000000000008 0.05 +0.2 0.03000000000000007 0.05 +0.2 0.05 0.03000000000000001 +0.2 0.05 0.009999999999999974 +0.2 0.05 -0.01 +0.2 0.05 -0.03000000000000001 +0.22 -0.05 -0.05 +0.2399999999999998 -0.05 -0.05 +0.2599999999999998 -0.05 -0.05 +0.2799999999999998 -0.05 -0.05 +0.2999999999999996 -0.05 -0.05 +0.3199999999999996 -0.05 -0.05 +0.3399999999999996 -0.05 -0.05 +0.3599999999999997 -0.05 -0.05 +0.3799999999999997 -0.05 -0.05 +0.3999999999999997 -0.05 -0.05 +0.4199999999999997 -0.05 -0.05 +0.4399999999999997 -0.05 -0.05 +0.46 -0.05 -0.05 +0.48 -0.05 -0.05 +0.5 -0.05 0.03000000000000001 +0.5 -0.05 0.009999999999999974 +0.5 -0.05 -0.01 +0.5 -0.05 -0.03000000000000001 +0.22 -0.05 0.05 +0.2399999999999998 -0.05 0.05 +0.2599999999999998 -0.05 0.05 +0.2799999999999998 -0.05 0.05 +0.2999999999999996 -0.05 0.05 +0.3199999999999996 -0.05 0.05 +0.3399999999999996 -0.05 0.05 +0.3599999999999997 -0.05 0.05 +0.3799999999999997 -0.05 0.05 +0.3999999999999997 -0.05 0.05 +0.4199999999999997 -0.05 0.05 +0.4399999999999997 -0.05 0.05 +0.46 -0.05 0.05 +0.48 -0.05 0.05 +0.22 0.05 -0.05 +0.2399999999999998 0.05 -0.05 +0.2599999999999998 0.05 -0.05 +0.2799999999999998 0.05 -0.05 +0.2999999999999996 0.05 -0.05 +0.3199999999999996 0.05 -0.05 +0.3399999999999996 0.05 -0.05 +0.3599999999999997 0.05 -0.05 +0.3799999999999997 0.05 -0.05 +0.3999999999999997 0.05 -0.05 +0.4199999999999997 0.05 -0.05 +0.4399999999999997 0.05 -0.05 +0.46 0.05 -0.05 +0.48 0.05 -0.05 +0.5 -0.02999999999999997 -0.05 +0.5 -0.009999999999999933 -0.05 +0.5 0.01000000000000008 -0.05 +0.5 0.03000000000000007 -0.05 +0.5 -0.02999999999999997 0.05 +0.5 -0.009999999999999933 0.05 +0.5 0.01000000000000008 0.05 +0.5 0.03000000000000007 0.05 +0.5 0.05 0.03000000000000001 +0.5 0.05 0.009999999999999974 +0.5 0.05 -0.01 +0.5 0.05 -0.03000000000000001 +0.22 0.05 0.05 +0.2399999999999998 0.05 0.05 +0.2599999999999998 0.05 0.05 +0.2799999999999998 0.05 0.05 +0.2999999999999996 0.05 0.05 +0.3199999999999996 0.05 0.05 +0.3399999999999996 0.05 0.05 +0.3599999999999997 0.05 0.05 +0.3799999999999997 0.05 0.05 +0.3999999999999997 0.05 0.05 +0.4199999999999997 0.05 0.05 +0.4399999999999997 0.05 0.05 +0.46 0.05 0.05 +0.48 0.05 0.05 +0.52 -0.05 -0.05 +0.54 -0.05 -0.05 +0.5600000000000001 -0.05 -0.05 +0.5800000000000001 -0.05 -0.05 +0.6000000000000001 -0.05 -0.05 +0.6200000000000001 -0.05 -0.05 +0.6400000000000001 -0.05 -0.05 +0.6600000000000001 -0.05 -0.05 +0.6800000000000002 -0.05 -0.05 +0.7000000000000004 -0.05 -0.05 +0.7200000000000004 -0.05 -0.05 +0.7400000000000004 -0.05 -0.05 +0.7600000000000005 -0.05 -0.05 +0.7800000000000005 -0.05 -0.05 +0.8000000000000007 -0.05 -0.05 +0.8200000000000007 -0.05 -0.05 +0.8400000000000005 -0.05 -0.05 +0.8600000000000003 -0.05 -0.05 +0.8800000000000001 -0.05 -0.05 +0.8999999999999999 -0.05 0.03000000000000001 +0.8999999999999999 -0.05 0.009999999999999974 +0.8999999999999999 -0.05 -0.01 +0.8999999999999999 -0.05 -0.03000000000000001 +0.52 -0.05 0.05 +0.54 -0.05 0.05 +0.5600000000000001 -0.05 0.05 +0.5800000000000001 -0.05 0.05 +0.6000000000000001 -0.05 0.05 +0.6200000000000001 -0.05 0.05 +0.6400000000000001 -0.05 0.05 +0.6600000000000001 -0.05 0.05 +0.6800000000000002 -0.05 0.05 +0.7000000000000004 -0.05 0.05 +0.7200000000000004 -0.05 0.05 +0.7400000000000004 -0.05 0.05 +0.7600000000000005 -0.05 0.05 +0.7800000000000005 -0.05 0.05 +0.8000000000000007 -0.05 0.05 +0.8200000000000007 -0.05 0.05 +0.8400000000000005 -0.05 0.05 +0.8600000000000003 -0.05 0.05 +0.8800000000000001 -0.05 0.05 +0.52 0.05 -0.05 +0.54 0.05 -0.05 +0.5600000000000001 0.05 -0.05 +0.5800000000000001 0.05 -0.05 +0.6000000000000001 0.05 -0.05 +0.6200000000000001 0.05 -0.05 +0.6400000000000001 0.05 -0.05 +0.6600000000000001 0.05 -0.05 +0.6800000000000002 0.05 -0.05 +0.7000000000000004 0.05 -0.05 +0.7200000000000004 0.05 -0.05 +0.7400000000000004 0.05 -0.05 +0.7600000000000005 0.05 -0.05 +0.7800000000000005 0.05 -0.05 +0.8000000000000007 0.05 -0.05 +0.8200000000000007 0.05 -0.05 +0.8400000000000005 0.05 -0.05 +0.8600000000000003 0.05 -0.05 +0.8800000000000001 0.05 -0.05 +0.8999999999999999 -0.02999999999999997 -0.05 +0.8999999999999999 -0.009999999999999933 -0.05 +0.8999999999999999 0.01000000000000008 -0.05 +0.8999999999999999 0.03000000000000007 -0.05 +0.8999999999999999 -0.02999999999999997 0.05 +0.8999999999999999 -0.009999999999999933 0.05 +0.8999999999999999 0.01000000000000008 0.05 +0.8999999999999999 0.03000000000000007 0.05 +0.8999999999999999 0.05 0.03000000000000001 +0.8999999999999999 0.05 0.009999999999999974 +0.8999999999999999 0.05 -0.01 +0.8999999999999999 0.05 -0.03000000000000001 +0.52 0.05 0.05 +0.54 0.05 0.05 +0.5600000000000001 0.05 0.05 +0.5800000000000001 0.05 0.05 +0.6000000000000001 0.05 0.05 +0.6200000000000001 0.05 0.05 +0.6400000000000001 0.05 0.05 +0.6600000000000001 0.05 0.05 +0.6800000000000002 0.05 0.05 +0.7000000000000004 0.05 0.05 +0.7200000000000004 0.05 0.05 +0.7400000000000004 0.05 0.05 +0.7600000000000005 0.05 0.05 +0.7800000000000005 0.05 0.05 +0.8000000000000007 0.05 0.05 +0.8200000000000007 0.05 0.05 +0.8400000000000005 0.05 0.05 +0.8600000000000003 0.05 0.05 +0.8800000000000001 0.05 0.05 +0.2 0 6.938893903907228e-18 +0.2 0.02125 -0.02125000000000002 +0.2 0.02124999999999999 0.02125000000000003 +0.2 -0.02125 -0.02124999999999998 +0.2 -0.02125 0.02125 +0.2 0.02960644531249999 -0.001032608695652179 +0.2 -0.02960644531250001 0.001032608695652165 +0.2 -0.001032608695652137 -0.0296064453125 +0.2 0.001032608695652186 0.02960644531250001 +0.2 0.03380541383219955 0.03380541383219955 +0.2 0.03355378256744874 -0.03355378256744874 +0.2 -0.03329166666666666 -0.03329166666666666 +0.2 -0.03380541383219955 0.03380541383219955 +0.2 0.01316566512554303 0.006965568849233099 +0.2 0.006896597168290011 -0.01314523077389088 +0.2 -0.007552916830449612 0.0116795375839983 +0.2 -0.01169529574984165 -0.007542366110451892 +0.2 0.03693237182893991 0.01880456102730947 +0.2 -0.01879372088509314 -0.03674995349702381 +0.2 0.03688204557598976 -0.01916727825262019 +0.2 -0.03693237182893991 0.01921760450557033 +0.2 -0.01880456102730945 0.03693237182893991 +0.2 -0.03682962239583333 -0.0187018115942029 +0.2 0.01875423477435936 -0.03688204557598976 +0.2 0.01921760450557038 0.03693237182893992 +0.2900000000000043 -0.05 6.938893903907228e-18 +0.4495964267981867 -0.05 0.0009169088628327299 +0.349139851518101 -0.05 -0.0001464334884532653 +0.4007143991606505 -0.05 0.0007908223265649036 +0.2451030258411362 -0.05 -7.632783294297951e-17 +0.3204639787837211 -0.05 -0.01565688133328609 +0.3216666666666661 -0.05 0.01700000000000046 +0.3740739549276746 -0.05 -0.01852581406415361 +0.3750000000000033 -0.05 0.01899999999999703 +0.4261049534852184 -0.05 0.01942495696653161 +0.4250000000000047 -0.05 -0.01899999999999891 +0.2664900310513914 -0.05 -0.02050493144185806 +0.2664900310513918 -0.05 0.02050493144185815 +0.4729869075930209 -0.05 -0.02031638426017986 +0.4712500000000002 -0.05 0.02124999999999884 +0.2276445959162137 -0.05 0.02432560059492064 +0.2276445959162152 -0.05 -0.02432560059491901 +0.3492035731755345 -0.05 -0.03058241945334793 +0.3494679284662798 -0.05 0.03052887672571537 +0.2923293782192862 -0.05 -0.02553412435614346 +0.2923293782192844 -0.05 0.0255341243561438 +0.4001351234688091 -0.05 -0.02768007823434574 +0.3994197102602035 -0.05 0.02432243664341316 +0.4474555729804497 -0.05 0.02328300978870497 +0.4439011022946344 -0.05 -0.02750221584936173 +0.2150443101179476 -0.05 1.110223024625157e-15 +0.4798908637073058 -0.05 -0.0008486017824942127 +0.2473202338888618 -0.05 0.02990294367184346 +0.2473202338888603 -0.05 -0.02990294367184278 +0.2669888326101091 -0.05 -2.498001805406602e-16 +0.3120573380649625 -0.05 0.0006367606375301191 +0.3299688783967307 -0.05 -0.03242454529602645 +0.4200854875081879 -0.05 -0.000207710914794379 +0.3703922427309692 -0.05 -0.000920587036317172 +0.3088936494485148 -0.05 0.03305280104440965 +0.3081431156972261 -0.05 -0.03246594685870385 +0.3296747221718246 -0.05 0.0001591408141784142 +0.3315781006805032 -0.05 0.03267199074568496 +0.3852350195485634 -0.05 -0.03325241620184339 +0.3843521786664335 -0.05 0.0347708657146336 +0.4289407617334988 -0.05 -0.03612256066222373 +0.4294489512611055 -0.05 0.0355288641405474 +0.3680575310901102 -0.05 -0.03256172256530996 +0.3673849939476297 -0.05 0.03308030076257966 +0.4832916666666651 -0.05 -0.03329166666666385 +0.4832916666666647 -0.05 0.03329166666666361 +0.3397139404891334 -0.05 -0.01527680407157502 +0.2788609428567401 -0.05 -0.03068108392466871 +0.2788609428567388 -0.05 0.03068108392466903 +0.3402266513987107 -0.05 0.01553721007827313 +0.2158074563538701 -0.05 -0.03419254364612884 +0.2158074563538681 -0.05 0.03419254364613063 +0.4136842298398604 -0.05 0.03493635394750037 +0.4136842298398602 -0.05 -0.03493635394750016 +0.3588308841981971 -0.05 -0.0153853602729991 +0.3595122790877814 -0.05 0.01383491704341379 +0.3854448066974736 -0.05 0.006040003601588212 +0.4348600000000089 -0.05 0.006026315789476128 +0.3027360043838265 -0.05 -0.0142032552511006 +0.4384126702306423 -0.05 -0.008997282888168701 +0.3896524559423644 -0.05 -0.01246495577382842 +0.2520372685332348 -0.05 0.01336693461130685 +0.252037268533233 -0.05 -0.01336693461130711 +0.4647554347826053 -0.05 0.006494565217394346 +0.3023985480738776 -0.05 0.01542373834712252 +0.2829008648535594 -0.05 -0.01515389916229518 +0.2828446221352339 -0.05 0.01535731301163221 +0.462022030886438 -0.05 -0.03421514252077462 +0.4620220308864371 -0.05 0.03421514252077372 +0.4587950623275474 -0.05 -0.01206687903153601 +0.4109500947654223 -0.05 0.01357528986720598 +0.4088885352285585 -0.05 -0.01478034720760904 +0.4872338875933986 -0.05 -0.01889133054186758 +0.4868865060747942 -0.05 0.01873861297683364 +0.2308168352869189 -0.05 0.03763790297949324 +0.2308168352869282 -0.05 -0.03763790297948662 +0.2123620970205056 -0.05 0.01918316471307978 +0.212362097020512 -0.05 -0.01918316471307059 +0.2665342415593981 -0.05 -0.03621779180767391 +0.2665342415593983 -0.05 0.03621779180767414 +0.232770833333334 -0.05 0.008947334864398068 +0.232770833333334 -0.05 -0.008947334864400559 +0.2908087420298426 -0.05 0.03913028246281694 +0.2907696680111427 -0.05 -0.03909972987088841 +0.2900000000000043 1.387778780781446e-17 -0.05 +0.4448112872718797 0.004147918173743562 -0.05 +0.3677323835401078 -0.001833795807332644 -0.05 +0.2451030258411357 3.469446951953614e-17 -0.05 +0.4097810820309147 0.007909073845413131 -0.05 +0.3297810820309186 -0.007909073845413929 -0.05 +0.4241304347826065 -0.01847826086956449 -0.05 +0.3441304347826069 0.0184782608695645 -0.05 +0.3934068950373262 -0.01995586297760238 -0.05 +0.3134068950373303 0.01995586297760389 -0.05 +0.2672222222222271 -0.02033333333333378 -0.05 +0.2672222222222269 0.02033333333333387 -0.05 +0.4711589841130377 0.02225136756686895 -0.05 +0.4712500000000017 -0.02125000000000065 -0.05 +0.2276445959162139 0.02432560059492017 -0.05 +0.2276445959162143 -0.02432560059491994 -0.05 +0.4376652860201597 0.01965445093210656 -0.05 +0.3855263157894726 0.02289473684210339 -0.05 +0.2998277680311046 -0.01725847399243435 -0.05 +0.3584132643582985 -0.01910676724233719 -0.05 +0.447295673076924 -0.02657138377926045 -0.05 +0.2903762447002849 0.0276920808659014 -0.05 +0.2150443101179458 -6.938893903907228e-18 -0.05 +0.4795780338402995 0.001174814127842261 -0.05 +0.3638693763948879 0.02704745720751903 -0.05 +0.2477767334071586 -0.02981302420423496 -0.05 +0.2477767334071572 0.02981302420423572 -0.05 +0.4099999999999977 0.03618261369442845 -0.05 +0.3299999999999996 -0.03618261369443022 -0.05 +0.3728911025416251 -0.03246664519500489 -0.05 +0.389623746357403 0.002657924619481625 -0.05 +0.3110142464737566 -0.0009430141049854013 -0.05 +0.2870312068354097 -0.03234119069260215 -0.05 +0.4262794966053576 0.001845373899697522 -0.05 +0.346820336461348 -0.001413183585991386 -0.05 +0.2672665710651743 -2.428926355210748e-05 -0.05 +0.4518819206966591 0.03303873592936089 -0.05 +0.4093927374726609 -0.03219330097982252 -0.05 +0.3293927374726677 0.03219330097982656 -0.05 +0.328475180704741 0.008986715760970578 -0.05 +0.4087690653810445 -0.009702508743732859 -0.05 +0.4299999999999968 -0.03527886056971442 -0.05 +0.3477254961034708 0.03540606885308085 -0.05 +0.483291666666668 0.03329166666666664 -0.05 +0.4832916666666673 -0.0332916666666664 -0.05 +0.3911381470103223 -0.03692316183048596 -0.05 +0.3099999999999987 0.0364489849948304 -0.05 +0.2699999999999978 -0.03672201414898065 -0.05 +0.2699999999999978 0.03672201414898239 -0.05 +0.3593196402461107 0.01161919148290735 -0.05 +0.2158074563538688 -0.0341925436461301 -0.05 +0.2158074563538683 0.03419254364613068 -0.05 +0.440068745262499 -0.01115766495233447 -0.05 +0.2521441511239164 0.01334610320899936 -0.05 +0.2521441511239182 -0.01334964391797124 -0.05 +0.458308491120774 0.01229545358542075 -0.05 +0.3778958799209504 -0.01391248729875245 -0.05 +0.2821684575945407 -0.01415167229017403 -0.05 +0.2979185416512342 0.01291643729999468 -0.05 +0.4568853717620629 -0.006893477140764832 -0.05 +0.28214121682941 0.01349561158278141 -0.05 +0.4615181382197173 -0.03401796712945108 -0.05 +0.3909594003752752 0.03694515224626352 -0.05 +0.3502233485485911 -0.03473017102196242 -0.05 +0.4299304885180721 0.03491680009264869 -0.05 +0.3094705417458146 -0.03440121306324422 -0.05 +0.4692665142952732 0.03771635403257929 -0.05 +0.4868239401013936 -0.01867337050776494 -0.05 +0.4865507812500025 0.0179908854166711 -0.05 +0.2308168352869218 0.03763790297949193 -0.05 +0.2308168352869213 -0.03763790297949165 -0.05 +0.2123620970205071 -0.0191831647130769 -0.05 +0.2123620970205062 0.01918316471307696 -0.05 +0.2327708333333318 0.008947334864396382 -0.05 +0.2327708333333318 -0.008947334864396618 -0.05 +0.3400357243916257 -0.02062500000000222 -0.05 +0.4009877114907801 0.02120241687461438 -0.05 +0.3199642756083747 -0.02062499999999853 -0.05 +0.4200357243916166 0.02062499999999627 -0.05 +0.3735516086794493 0.01325494165529158 -0.05 +0.3758645990126113 0.03660789833938942 -0.05 +0.5 0 6.938893903907228e-18 +0.5 0.02125 -0.02125000000000002 +0.5 0.02124999999999999 0.02125000000000003 +0.5 -0.02125 -0.02124999999999998 +0.5 -0.02125 0.02125 +0.5 0.02960644531249999 -0.001032608695652179 +0.5 -0.02960644531250001 0.001032608695652165 +0.5 -0.001032608695652137 -0.0296064453125 +0.5 0.001032608695652186 0.02960644531250001 +0.5 0.03380541383219955 0.03380541383219955 +0.5 0.03355378256744874 -0.03355378256744874 +0.5 -0.03329166666666666 -0.03329166666666666 +0.5 -0.03380541383219955 0.03380541383219955 +0.5 0.01316566512554303 0.006965568849233099 +0.5 0.006896597168290011 -0.01314523077389088 +0.5 -0.007552916830449612 0.0116795375839983 +0.5 -0.01169529574984165 -0.007542366110451892 +0.5 0.03693237182893991 0.01880456102730947 +0.5 -0.01879372088509314 -0.03674995349702381 +0.5 0.03688204557598976 -0.01916727825262019 +0.5 -0.03693237182893991 0.01921760450557033 +0.5 -0.01880456102730945 0.03693237182893991 +0.5 -0.03682962239583333 -0.0187018115942029 +0.5 0.01875423477435936 -0.03688204557598976 +0.5 0.01921760450557038 0.03693237182893992 +0.2900000000000043 6.938893903907228e-18 0.05 +0.4490810307978683 -0.0004020423781639776 0.05 +0.3485061176172071 -0.0001464334884540286 0.05 +0.3999999999999995 9.020562075079397e-17 0.05 +0.2451030258411355 5.551115123125783e-17 0.05 +0.3204639787837189 -0.01565688133328722 0.05 +0.3216666666666659 0.01700000000000046 0.05 +0.4249999999999992 -0.01900000000000025 0.05 +0.425300954731922 0.01880913865839685 0.05 +0.3749999999999989 -0.01899999999999966 0.05 +0.3749999999999987 0.01899999999999968 0.05 +0.2664900310513914 -0.02050493144185828 0.05 +0.2664900310513914 0.02050493144185832 0.05 +0.4712500000000017 0.0212500000000007 0.05 +0.4729869075930226 -0.02031638426018268 0.05 +0.2276445959162139 0.02432560059492017 0.05 +0.2276445959162139 -0.02432560059492003 0.05 +0.3496363077833504 -0.03277497942313506 0.05 +0.3500064051903948 0.03270001960444856 0.05 +0.2923293782192866 0.02553412435614343 0.05 +0.2923293782192862 -0.02553412435614346 0.05 +0.4006336305784617 -0.02427267975913415 0.05 +0.3997712383386043 0.02685850486126824 0.05 +0.4462246706469046 -0.02920910293075929 0.05 +0.4477854910714305 0.02710379464285459 0.05 +0.2150443101179458 -6.938893903907228e-18 0.05 +0.4798908637073087 -0.0008486017824934841 0.05 +0.2473202338888607 0.0299029436718439 0.05 +0.2473202338888607 -0.02990294367184394 0.05 +0.2669888326101084 -4.85722573273506e-17 0.05 +0.3120573380649614 0.0006367606375290713 0.05 +0.3312186981212961 -0.03228311875218079 0.05 +0.4292564815195088 0.0008827082831198013 0.05 +0.3820082853088831 1.110223024625157e-16 0.05 +0.3088936494485155 0.03305280104440876 0.05 +0.308321661372164 -0.03244574306672574 0.05 +0.3295690998550069 0.0001591408141776718 0.05 +0.3297534516021905 0.03292026906881633 0.05 +0.4147649804514337 0.03325241620184534 0.05 +0.415298844149512 -0.03493630467082386 0.05 +0.3684641194720624 -0.03328683650719066 0.05 +0.3685258023732372 0.03327434320407648 0.05 +0.4316240251216505 0.03336015647582986 0.05 +0.4313442234467879 -0.03326738729327978 0.05 +0.483291666666668 0.03329166666666664 0.05 +0.4832916666666673 -0.0332916666666664 0.05 +0.3398711401749108 -0.0156186596425654 0.05 +0.2788609428567395 0.03068108392466881 0.05 +0.2788609428567403 -0.03068108392466854 0.05 +0.3398890633033926 0.01594044694525022 0.05 +0.2158074563538688 -0.0341925436461301 0.05 +0.2158074563538683 0.03419254364613068 0.05 +0.3863157701601385 -0.03493635394749635 0.05 +0.3863157701601387 0.03493635394749829 0.05 +0.357899213607028 -0.016804484843558 0.05 +0.3579741641798111 0.01679472937755296 0.05 +0.4151399999999976 -0.006026315789474948 0.05 +0.3027468489947915 -0.01420202810144128 0.05 +0.4106248078630657 0.01228612174502246 0.05 +0.2520372685332311 -0.01336693461130864 0.05 +0.2520372685332313 0.01336693461130875 0.05 +0.44014 0.01283675638290768 0.05 +0.4398933512919982 -0.01438371907328255 0.05 +0.4610690216587816 0.007069014226202777 0.05 +0.3023985480738771 0.01542373834712084 0.05 +0.2828446221352343 0.01535731301163189 0.05 +0.2829026722887202 -0.01515369463735193 0.05 +0.4620220308864373 -0.03421514252077639 0.05 +0.4620220308864369 0.0342151425207764 0.05 +0.4587382680831886 -0.01318656838849366 0.05 +0.3901399999999933 -0.01222640000000295 0.05 +0.391235246740703 0.01390349018314622 0.05 +0.4872338875933997 -0.01889133054186849 0.05 +0.4868865060747956 0.0187386129768348 0.05 +0.2308168352869218 0.03763790297949193 0.05 +0.2308168352869213 -0.03763790297949165 0.05 +0.2123620970205071 -0.0191831647130769 0.05 +0.2123620970205062 0.01918316471307696 0.05 +0.2665342415593983 -0.03621779180767416 0.05 +0.2665342415593983 0.03621779180767422 0.05 +0.2327708333333318 0.008947334864396382 0.05 +0.2327708333333318 -0.008947334864396618 0.05 +0.3659175965946391 -3.198830089701232e-15 0.05 +0.2908087420298466 0.03913028246281489 0.05 +0.2907789633919724 -0.03909867802832333 0.05 +0.2900000000000043 0.05 -1.387778780781446e-17 +0.4448112872718821 0.05 -0.004147918173743881 +0.3677323835401085 0.05 0.001833795807333449 +0.2451030258411362 0.05 -2.081668171172169e-17 +0.4097810820309173 0.05 -0.007909073845413173 +0.3297810820309177 0.05 0.007909073845414102 +0.344130434782606 0.05 -0.01847826086956397 +0.4241304347826123 0.05 0.01847826086956572 +0.3934068950373304 0.05 0.01995586297760006 +0.3134068950373294 0.05 -0.01995586297760448 +0.2672222222222271 0.05 -0.02033333333333379 +0.2672222222222269 0.05 0.02033333333333383 +0.4712500000000013 0.05 0.02125000000000039 +0.4711589841130359 0.05 -0.02225136756686717 +0.2276445959162134 0.05 0.02432560059492071 +0.2276445959162154 0.05 -0.02432560059491894 +0.4376652860201622 0.05 -0.01965445093210608 +0.3855263157894726 0.05 -0.02289473684210335 +0.2998277680311059 0.05 0.01725847399243437 +0.3584132643582985 0.05 0.01910676724233749 +0.4472956730769266 0.05 0.02657138377926392 +0.2903762447002842 0.05 -0.02769208086590023 +0.2150443101179476 0.05 1.110223024625157e-15 +0.4795780338402991 0.05 -0.001174814127840366 +0.3638693763948884 0.05 -0.0270474572075187 +0.247776733407157 0.05 -0.02981302420423371 +0.2477767334071572 0.05 0.02981302420423565 +0.4099999999999988 0.05 -0.03618261369442902 +0.3299999999999992 0.05 0.03618261369443045 +0.3728911025416262 0.05 0.03246664519500463 +0.3896237463574055 0.05 -0.002657924619481486 +0.311014246473758 0.05 0.0009430141049838539 +0.2870312068354102 0.05 0.03234119069260262 +0.4262794966053616 0.05 -0.001845373899697883 +0.3468203364613467 0.05 0.001413183585991906 +0.2672665710651747 0.05 2.428926355256544e-05 +0.4518819206966578 0.05 -0.03303873592935942 +0.4093927374726642 0.05 0.03219330097982337 +0.3293927374726648 0.05 -0.03219330097982517 +0.3284751807047375 0.05 -0.008986715760969724 +0.4087690653810485 0.05 0.009702508743732761 +0.4299999999999966 0.05 0.03527886056971641 +0.3477254961034699 0.05 -0.03540606885308062 +0.4832916666666676 0.05 0.03329166666666662 +0.4832916666666678 0.05 -0.03329166666666668 +0.3911381470103241 0.05 0.03692316183048562 +0.3099999999999989 0.05 -0.03644898499482901 +0.2699999999999978 0.05 -0.0367220141489806 +0.2699999999999978 0.05 0.03672201414898238 +0.359319640246111 0.05 -0.01161919148290647 +0.2158074563538701 0.05 -0.03419254364612884 +0.2158074563538681 0.05 0.03419254364613063 +0.4400687452625027 0.05 0.01115766495233261 +0.2521441511239164 0.05 0.01334964391797196 +0.25214415112392 0.05 -0.01334610320899713 +0.458308491120774 0.05 -0.01229545358542032 +0.3778958799209526 0.05 0.01391248729875244 +0.2821684575945436 0.05 0.01415167229017517 +0.2979185416512338 0.05 -0.01291643729999625 +0.456885371762064 0.05 0.006893477140765381 +0.2821412168294097 0.05 -0.01349561158278301 +0.4615181382197235 0.05 0.03401796712945405 +0.4299304885180733 0.05 -0.03491680009264916 +0.3909594003752752 0.05 -0.03694515224626388 +0.3502233485485906 0.05 0.03473017102196242 +0.309470541745815 0.05 0.03440121306324419 +0.4692665142952723 0.05 -0.03771635403257866 +0.4868239401013936 0.05 0.01867337050776532 +0.4865507812500003 0.05 -0.01799088541666431 +0.2308168352869189 0.05 0.03763790297949324 +0.2308168352869282 0.05 -0.03763790297948662 +0.2123620970205056 0.05 0.01918316471307978 +0.212362097020512 0.05 -0.01918316471307059 +0.232770833333334 0.05 0.008947334864398068 +0.232770833333334 0.05 -0.008947334864400559 +0.4009877114907818 0.05 -0.02120241687461523 +0.4200357243916222 0.05 -0.02062500000000046 +0.340035724391621 0.05 0.02062500000000195 +0.3199642756083763 0.05 0.02062499999999787 +0.3735516086794508 0.05 -0.01325494165529041 +0.3758645990126119 0.05 -0.03660789833939009 +0.8321378605607404 -0.05 0.002373713138257433 +0.5499999999999978 -0.05 -6.938893903907228e-18 +0.6902587843762817 -0.05 -0.002115946913903967 +0.6079793554399917 -0.05 -0.0003237681143339957 +0.7500000000000058 -0.05 6.938893903907228e-18 +0.6502189179690838 -0.05 0.007909073845411216 +0.7897810820309208 -0.05 -0.007909073845412617 +0.8627505575241243 -0.05 -0.0125008630121328 +0.7230249584691091 -0.05 -0.01698010483594569 +0.5795202027983914 -0.05 0.0176774624849456 +0.5801890553934381 -0.05 -0.01625879407230577 +0.7199485508363008 -0.05 0.0182596423476834 +0.8678839514720753 -0.05 0.01865059252466765 +0.8041304347826146 -0.05 0.01847826086956508 +0.6366804763979268 -0.05 -0.01746033174732707 +0.6660702179218543 -0.05 -0.01809750074906488 +0.7739297820781497 -0.05 0.01809750074906823 +0.5284483008914875 -0.05 0.01910140289178507 +0.527240000571626 -0.05 -0.02019363350958675 +0.6256589301903599 -0.05 0.0222693953854239 +0.8144736842105285 -0.05 -0.02289473684210287 +0.674460448736663 -0.05 0.02262898827986537 +0.7657537946496527 -0.05 -0.02185198400699865 +0.8418276773850915 -0.05 0.02200312437061647 +0.6097338986901284 -0.05 -0.03087581283819753 +0.8415812727226024 -0.05 -0.02484435788526305 +0.7483286107328275 -0.05 0.02566572214656188 +0.691671389267176 -0.05 -0.02566572214656558 +0.5583789803631634 -0.05 0.02650407369374448 +0.5553428824322157 -0.05 -0.02907838838831193 +0.7007577269814749 -0.05 0.02560456507343932 +0.6007273649357148 -0.05 0.02662780801435102 +0.7408580300966683 -0.05 -0.02651230019426657 +0.5200784293916114 -0.05 -0.001080474544098764 +0.8806530937951673 -0.05 0.0007531254745326149 +0.8512368901849072 -0.05 0.003831457726565055 +0.8782674193679254 -0.05 -0.0284518138670425 +0.650062190245456 -0.05 0.03614940531093479 +0.7900621902454565 -0.05 -0.036149405310935 +0.6702101782623648 -0.05 0.002998967982295687 +0.7698509344253914 -0.05 -0.003164990193708514 +0.8219388858695016 -0.05 0.02911925268822119 +0.6306092589647216 -0.05 0.003313380254134315 +0.8095286732760965 -0.05 -0.003041480584786142 +0.7884245706012001 -0.05 0.0309817582044989 +0.6513164530159028 -0.05 -0.03092266530667913 +0.5899376729874148 -0.05 -0.03272091507399801 +0.7079913866087402 -0.05 0.003663711072773905 +0.5885375649835938 -0.05 -0.0006113194502086888 +0.7078885644829358 -0.05 -0.03302350321800963 +0.5702655246678614 -0.05 -0.0003814678025901366 +0.7300669702105398 -0.05 0.0006108856715357908 +0.7326616275229167 -0.05 0.03324463278070028 +0.857971020607788 -0.05 -0.0324676326993145 +0.7892742461990623 -0.05 0.008906995866537482 +0.6511053748571043 -0.05 -0.008681000044193622 +0.5704680991794007 -0.05 -0.03393932159026468 +0.5731372803666981 -0.05 0.03518582194503753 +0.8815850852272742 -0.05 0.03158508522727399 +0.6297594375367763 -0.05 -0.03296762800708612 +0.8539319801831196 -0.05 0.03506421802113395 +0.5399990085569415 -0.05 0.03385809327043943 +0.5167083333333322 -0.05 -0.03329166666666676 +0.5167083333333351 -0.05 0.03329166666666346 +0.726354310609743 -0.05 -0.03530318164964438 +0.8256383707462061 -0.05 -0.03347754132001906 +0.7146735810681386 -0.05 0.03542176804036461 +0.6760898755569422 -0.05 -0.0332241928554311 +0.7641441678373182 -0.05 0.03313482690082502 +0.5994376657832561 -0.05 -0.01563176825817431 +0.8066511202670532 -0.05 0.0348400418460857 +0.6202484472049719 -0.05 -0.01300000000000188 +0.7012732714391032 -0.05 -0.01449150913932874 +0.8207980021748202 -0.05 0.01332266131776584 +0.539737190530887 -0.05 -0.03352675153138894 +0.5877001027597162 -0.05 0.03600646287141353 +0.6854589920421144 -0.05 0.03477100775431617 +0.8853255534211188 -0.05 0.01666530738729603 +0.536858717626302 -0.05 0.004531490926789963 +0.6812620893145258 -0.05 -0.01345630821757024 +0.7576758518881168 -0.05 0.01433606659527224 +0.6150351600645849 -0.05 0.03487175721296643 +0.7550351600645888 -0.05 -0.03487175721296538 +0.7381738097588475 -0.05 0.01474390907254976 +0.5418528874358639 -0.05 -0.01331821355915946 +0.8088345201897402 -0.05 -0.03620970262773131 +0.6683362259026426 -0.05 0.03569573355752009 +0.5128053526593137 -0.05 -0.01891315494407046 +0.513344521221184 -0.05 0.01806159386788235 +0.7718025700946796 -0.05 -0.03558302442181625 +0.631786759351463 -0.05 0.03565259298488688 +0.8851318187553352 -0.05 -0.0145784731132428 +0.8425815940694457 -0.05 -0.008965555028159697 +0.827775267544105 -0.05 -0.01520331210946636 +0.6881895861679397 -0.05 0.01459188220813107 +0.6123821496288024 -0.05 0.01509655793473812 +0.7523821496288043 -0.05 -0.01509655793472747 +0.5625089523928237 -0.05 -0.01470437717087976 +0.5978293275572988 -0.05 0.01169334817389841 +0.8660779880802205 -0.05 0.003876017813088987 +0.8350431906571154 -0.05 0.03620134113971572 +0.6588753727874312 -0.05 0.0210011948293372 +0.7987740709268532 -0.05 -0.02113823320182772 +0.7810041070621589 -0.05 -0.02096611849678313 +0.6412019049180859 -0.05 0.0210491737683547 +0.5596333333333399 -0.05 0.01078358208954785 +0.5448152482525839 -0.05 0.01662107383869836 +0.7392664216810254 -0.05 -0.01159561545868078 +0.7497466891968525 -0.05 0.03946024207496802 +0.6902941393850019 -0.05 -0.03945338224531343 +0.8690302629089102 -0.05 0.03782932513743939 +0.8880150464595844 -0.05 -0.03906222609984425 +0.8700000000000017 -0.05 -0.03992983203099495 +0.8310875366804336 -0.001850505842799943 -0.05 +0.6900000000000059 0.001275159787391976 -0.05 +0.5517275157801924 0.0002864022317890375 -0.05 +0.6099999999999988 6.938893903907228e-18 -0.05 +0.772020644560012 0.0003237681143317961 -0.05 +0.6502189179690827 -0.007909073845411736 -0.05 +0.729781082030921 -0.007909073845413048 -0.05 +0.8644862411419214 0.0140797799247685 -0.05 +0.8006122634370751 -0.01832772151438823 -0.05 +0.5828009980802886 -0.01676177118566551 -0.05 +0.5809246860786819 0.01735760799431746 -0.05 +0.800548649301468 0.01620148156933793 -0.05 +0.8678839514720753 -0.01865059252466786 -0.05 +0.7433195236020766 0.01746033174732486 -0.05 +0.636680476397925 0.01746033174732721 -0.05 +0.6665931049626701 0.01995586297759731 -0.05 +0.713406895037332 0.01995586297760286 -0.05 +0.5272747761227583 0.0198239322871868 -0.05 +0.5284483008914873 -0.01910140289178262 -0.05 +0.6256589301903657 -0.02226939538542087 -0.05 +0.6744736842105277 -0.02289473684210286 -0.05 +0.7055263157894791 -0.02289473684210608 -0.05 +0.7543410698096449 -0.02226939538542404 -0.05 +0.8407871802637168 -0.02017759645574541 -0.05 +0.8308130157365903 0.03192797706082313 -0.05 +0.6100822641160957 0.03262567416828464 -0.05 +0.7702661013098724 0.03087581283819653 -0.05 +0.557992890369915 0.02373006671073612 -0.05 +0.5561419906744474 -0.02603447935339108 -0.05 +0.6900000000000033 0.0275241854392022 -0.05 +0.6011846653893247 -0.02645232261956796 -0.05 +0.7794889318029581 -0.02647784698379384 -0.05 +0.8200745342907965 -0.02766771462713175 -0.05 +0.5202188001929049 0.001170285748702135 -0.05 +0.8810030077451052 -0.001060845292741294 -0.05 +0.8512368901849097 -0.003831457726569037 -0.05 +0.8508152866242125 0.03073089171974577 -0.05 +0.8787797619047644 0.02877976190476461 -0.05 +0.650062190245458 -0.03614940531093148 -0.05 +0.7299378097545459 -0.03614940531093395 -0.05 +0.7094267823982583 -0.003067356081196564 -0.05 +0.6705732176017469 -0.003067356081197292 -0.05 +0.6308618395347227 -0.003353851268425072 -0.05 +0.7493907410352825 -0.003313380254136869 -0.05 +0.729283557051593 0.03110756079432805 -0.05 +0.6507164429484069 0.03110756079432717 -0.05 +0.7911159039348563 0.03270611348550345 -0.05 +0.7916074635048054 0.0004933908614716473 -0.05 +0.5707285196777274 0.001490553289198365 -0.05 +0.5901281915787502 0.0007848614461355014 -0.05 +0.810365254434315 -9.951016292310266e-05 -0.05 +0.6900000000000066 -0.03384517118037716 -0.05 +0.5913044060138621 0.03284184260018676 -0.05 +0.8100744193313913 0.03260205730953739 -0.05 +0.8410679862305834 0.0143055761462547 -0.05 +0.7286885569823698 0.008828326913135072 -0.05 +0.6514496633346818 0.008763171149061791 -0.05 +0.5726479564792724 -0.03300000000000607 -0.05 +0.8815850852272742 -0.03158508522727448 -0.05 +0.5740443964924919 0.03478590346104807 -0.05 +0.7942384688090673 -0.03479847514953954 -0.05 +0.7503119922331658 0.03298963937466266 -0.05 +0.6297294798413557 0.03319795619967368 -0.05 +0.8535502485107886 -0.03482350562881511 -0.05 +0.5404351392812208 0.03338273728534054 -0.05 +0.5402314631040503 -0.0335931780850941 -0.05 +0.5167083333333318 0.03329166666666694 -0.05 +0.5167083333333349 -0.03329166666666357 -0.05 +0.6700000000000033 0.03644898499482484 -0.05 +0.7099999999999989 0.03644898499482647 -0.05 +0.6900000000000066 -0.01575370325433203 -0.05 +0.7808850525676747 0.01560009447813997 -0.05 +0.6199808644128915 0.01372482310272417 -0.05 +0.760084952877375 0.01369139014553371 -0.05 +0.6004034020333795 0.01622246821860807 -0.05 +0.8206594769524636 0.01551451268003835 -0.05 +0.5873267239897775 -0.03524281876104791 -0.05 +0.5388156144940635 0.01198314317439427 -0.05 +0.6821080365436152 0.01307983916600032 -0.05 +0.6979346199098795 0.01303011223060745 -0.05 +0.8853510573533321 -0.0166877359454764 -0.05 +0.536436191650935 -0.004868845795109447 -0.05 +0.6150351600645927 -0.03487175721296268 -0.05 +0.764964839935419 -0.03487175721296331 -0.05 +0.8336079182914664 -0.03619762489468559 -0.05 +0.6700000000000035 -0.03792284108329081 -0.05 +0.7099999999999989 -0.03792284108329202 -0.05 +0.5128403819297991 0.0188571769405112 -0.05 +0.5134492187500062 -0.01799088541665611 -0.05 +0.7482132406485391 -0.03565259298488723 -0.05 +0.6317867593514654 -0.03565259298488439 -0.05 +0.8851318187553407 0.01457847311324692 -0.05 +0.8204235927273249 -0.01234188656195083 -0.05 +0.6123821496288118 -0.01509655793473808 -0.05 +0.7676178503712052 -0.01509655793473717 -0.05 +0.8652117549743681 0.03569226876146533 -0.05 +0.807998645321971 -0.0369721891361354 -0.05 +0.5647095222180696 -0.01375948082176457 -0.05 +0.7821254078753384 -0.01169815680752719 -0.05 +0.8661312270486365 -0.002797275735742594 -0.05 +0.6592153809391992 -0.02142806886048759 -0.05 +0.7386047031478855 -0.02098647463013162 -0.05 +0.7205461155201811 -0.02148831463217889 -0.05 +0.641300669705049 -0.02112706460926019 -0.05 +0.5453362772463866 -0.01689397167715631 -0.05 +0.599299200935435 -0.01150515805876721 -0.05 +0.8686038570420278 -0.03701183667615149 -0.05 +0.8894524187327479 0.03945241873274803 -0.05 +0.9 -2.081668171172169e-17 0 +0.9 0.02020496156150939 -0.02050978155237251 +0.9 0.02124999999999998 0.02125000000000002 +0.9 -0.02125000000000001 0.02124999999999999 +0.9 -0.01931502068759285 -0.0202136941733215 +0.9 0.02947581550768866 0.001125136001605603 +0.9 -0.02959793649133873 0.0006385404004634471 +0.9 0.0003267730425169715 -0.03175621508070525 +0.9 -1.387778780781446e-17 0.02951086956521737 +0.9 0.03329166666666666 -0.03329166666666666 +0.9 0.03355378256744873 0.03355378256744873 +0.9 -0.03355378256744874 0.03355378256744874 +0.9 -0.03329166666666668 -0.03329166666666668 +0.9 0.01257123525636518 -0.004624825140792793 +0.9 0.009109493773326205 0.009978515383655615 +0.9 -0.01210735427507084 -0.004958543873477973 +0.9 0.03685591961502747 0.01918578371381087 +0.9 0.03659448874717296 -0.01853526244348671 +0.9 -0.01799088541666665 0.03655078124999997 +0.9 -0.01816038157034081 -0.03673355600733919 +0.9 -0.036718925414162 0.01855087479264408 +0.9 -0.03644092476911966 -0.01857336408790495 +0.9 0.01876468025413862 -0.03711153265994888 +0.9 0.01799088541666664 0.03655078124999997 +0.9 -0.008878810534632749 0.01031942499738414 +0.9 0.001571787787819454 -0.01436248356328276 +0.8305210351121499 0.0009970936685603782 0.05 +0.6925276871495811 0.0005875412764432819 0.05 +0.5517275157801924 0.0002864022317890375 0.05 +0.6099999999999988 6.938893903907228e-18 0.05 +0.7500000000000056 6.938893903907228e-18 0.05 +0.6502189179690827 -0.007909073845411736 0.05 +0.7897810820309212 -0.00790907384541209 0.05 +0.864486241141921 0.01407977992476822 0.05 +0.5828009980802886 -0.01676177118566551 0.05 +0.7195240289655329 -0.01815230641477063 0.05 +0.5809246860786819 0.01735760799431746 0.05 +0.7205312493638552 0.01651976499017867 0.05 +0.8678839514720758 -0.01865059252466782 0.05 +0.8033195236020778 0.01746033174732883 0.05 +0.636680476397925 0.01746033174732721 0.05 +0.6660702179218547 0.0180975007490637 0.05 +0.7739297820781526 0.01809750074906918 0.05 +0.5272747761227583 0.0198239322871868 0.05 +0.5284483008914873 -0.01910140289178262 0.05 +0.6256589301903657 -0.02226939538542087 0.05 +0.6742462053503528 -0.02185198400700079 0.05 +0.8144736842105316 -0.02289473684210341 0.05 +0.765753794649654 -0.02185198400699826 0.05 +0.8432329501405371 -0.02411901819894849 0.05 +0.8307307516204903 0.03206192308244722 0.05 +0.6100822641160957 0.03262567416828464 0.05 +0.7483286107328313 0.02566572214656375 0.05 +0.6916713892671815 0.0256657221465644 0.05 +0.557992890369915 0.02373006671073612 0.05 +0.5561419906744474 -0.02603447935339108 0.05 +0.6011846653893247 -0.02645232261956796 0.05 +0.6982418420070382 -0.02608343647472727 0.05 +0.7400639073550661 -0.02665945653226979 0.05 +0.5202188001929049 0.001170285748702135 0.05 +0.8810030077451043 -0.001060845292742273 0.05 +0.8507150027352013 -0.004097427140514087 0.05 +0.8508152866242116 0.03073089171974565 0.05 +0.8787797619047641 0.02877976190476457 0.05 +0.6500000000000021 -0.03611619692743553 0.05 +0.7900621902454568 -0.03614940531093545 0.05 +0.7698509344253925 -0.003164990193708084 0.05 +0.6704650264683103 -0.003091547534154956 0.05 +0.6308618395347227 -0.003353851268425072 0.05 +0.8093431622650322 -0.003390996506616388 0.05 +0.7886835469841014 0.03092266530668238 0.05 +0.6513164530159012 0.03092266530667948 0.05 +0.7117978336203079 0.0006679622712910949 0.05 +0.5707285196777274 0.001490553289198365 0.05 +0.7082211333807487 0.03324707959996208 0.05 +0.5901281915787502 0.0007848614461355014 0.05 +0.7295752976185714 0.0002126979599116063 0.05 +0.5913044060138621 0.03284184260018676 0.05 +0.7320476669455402 0.03280821476124067 0.05 +0.8411699783381679 0.0144620435425012 0.05 +0.7888962363235561 0.008651995465160295 0.05 +0.6511657830447151 0.008665160691079032 0.05 +0.5726479564792724 -0.03300000000000607 0.05 +0.8815850852272735 -0.03158508522727388 0.05 +0.5740443964924919 0.03478590346104807 0.05 +0.7257261320880803 -0.03543813272150705 0.05 +0.6298009096112955 0.03317594483209657 0.05 +0.8102958779763929 0.03310883160759133 0.05 +0.8260518082678732 -0.0334503446960773 0.05 +0.856914195706173 -0.03452914972593515 0.05 +0.5404351392812208 0.03338273728534054 0.05 +0.5402314631040503 -0.0335931780850941 0.05 +0.5167083333333318 0.03329166666666694 0.05 +0.5167083333333349 -0.03329166666666357 0.05 +0.6760898755569471 0.03322419285543253 0.05 +0.7639101244430602 0.03322419285543256 0.05 +0.6199839633720898 0.01372386814612724 0.05 +0.8208967214857186 0.01578320452363542 0.05 +0.6004039185265795 0.01622230905917525 0.05 +0.5873267239897775 -0.03524281876104791 0.05 +0.5388156144940635 0.01198314317439427 0.05 +0.7022428678783683 0.01551745379788143 0.05 +0.8853510573533285 -0.01668773594547769 0.05 +0.536436191650935 -0.004868845795109447 0.05 +0.711288837182104 -0.03658149723549241 0.05 +0.6822395151950635 0.01424397947486633 0.05 +0.7576479895792776 0.01434670539939428 0.05 +0.6849648399354182 -0.03487175721296441 0.05 +0.6150351600645927 -0.03487175721296268 0.05 +0.7550351600645913 -0.03487175721296423 0.05 +0.8286042152561712 -0.01576547205212685 0.05 +0.7381403551335675 0.01458818480843325 0.05 +0.8088837389423198 -0.03620646493440625 0.05 +0.5128403819297991 0.0188571769405112 0.05 +0.5134492187500062 -0.01799088541665611 0.05 +0.6682077949462322 -0.03557748969123341 0.05 +0.7718025700946791 -0.03558302442181648 0.05 +0.6317763943105561 -0.03564705825430173 0.05 +0.8851318187553379 0.01457847311324213 0.05 +0.6876178503712058 -0.01509655793473062 0.05 +0.6123821496288118 -0.01509655793473808 0.05 +0.7523821496288077 -0.01509655793473061 0.05 +0.865211754974363 0.03569226876146227 0.05 +0.5647095222180696 -0.01375948082176457 0.05 +0.7019418484227331 -0.01161535945529883 0.05 +0.866049448638057 -0.003139412427988937 0.05 +0.7987513555504391 -0.02119594623991241 0.05 +0.6591890427240763 -0.0207942014291937 0.05 +0.7810003211660903 -0.0209757373364638 0.05 +0.6412841874548008 -0.02101496285169811 0.05 +0.5453362772463866 -0.01689397167715631 0.05 +0.599299200935435 -0.01150515805876721 0.05 +0.7383090767135965 -0.01193912458437189 0.05 +0.6900000000000044 0.0398301765166101 0.05 +0.7497025407185292 0.03944217397496458 0.05 +0.8699054117399607 -0.03975269009450428 0.05 +0.8890670707730504 0.03906707077305052 0.05 +0.8307624630947812 0.05 -0.002191815003420423 +0.5499999999999978 0.05 6.938893903907228e-18 +0.6900000000000046 0.05 1.387778780781446e-17 +0.6101415585072154 0.05 -0.001940924322205925 +0.7720206445600157 0.05 0.0003237681143321985 +0.6502189179690838 0.05 0.007909073845411216 +0.7297810820309203 0.05 -0.007909073845412208 +0.8644862411419203 0.05 -0.01407977992476856 +0.7975500767972925 0.05 -0.01690705787505283 +0.5765892216429072 0.05 -0.01634775030397676 +0.5797707002098629 0.05 0.01786991547438758 +0.8028015185915012 0.05 0.01775398276744991 +0.8678839514720753 0.05 0.01865059252466765 +0.7433195236020786 0.05 0.01746033174732685 +0.6366804763979268 0.05 -0.01746033174732707 +0.6665931049626699 0.05 -0.0199558629775973 +0.7134068950373333 0.05 0.01995586297760228 +0.5272400005716245 0.05 0.02019363350958545 +0.5284483008914884 0.05 -0.01910140289178482 +0.6255286655128907 0.05 0.02267253128167784 +0.6786583266160653 0.05 0.01878888988685118 +0.7013416733839379 0.05 -0.01878888988684943 +0.7543410698096489 0.05 -0.02226939538542481 +0.8416531361405943 0.05 0.02167113046138587 +0.8301271899750899 0.05 -0.02645404741411434 +0.6097683321471008 0.05 -0.03253237058946489 +0.7702661013098731 0.05 0.03087581283819711 +0.5574628317734911 0.05 -0.02590156609645072 +0.5553428824322106 0.05 0.02907838838831313 +0.5992465818627188 0.05 0.02559592328823722 +0.7789664740826954 0.05 -0.02633381277782919 +0.5200784293916103 0.05 0.001080474544098299 +0.8206575885434664 0.05 0.02868153548192515 +0.8810030077451037 0.05 0.001060845292741586 +0.8512368901849072 0.05 0.003831457726565055 +0.85081528662421 0.05 -0.0307308917197464 +0.8787797619047646 0.05 -0.02877976190476514 +0.6499999999999999 0.05 0.03618261369443065 +0.7299378097545457 0.05 -0.03614940531093432 +0.6870738885644068 0.05 -0.03242123414421826 +0.6929261114355942 0.05 0.03242123414422104 +0.711595709311152 0.05 -0.0007037364881210817 +0.6684042906888485 0.05 0.0007037364881236768 +0.6308612670460132 0.05 0.00316297333389752 +0.7493907410352851 0.05 -0.00331338025413596 +0.7292835570515939 0.05 0.03110756079432928 +0.650716442948408 0.05 -0.03110756079432741 +0.7892606794029986 0.05 0.03247928664342881 +0.7914725772798497 0.05 0.0009889183343794045 +0.5920712354310524 0.05 0.003662488105252493 +0.8104692576506416 0.05 -0.03219232381019625 +0.5898938713525652 0.05 -0.03261560638293168 +0.5695346748800654 0.05 0.0003592604233327579 +0.8101778894079064 0.05 -0.0004390483102640758 +0.8454856142041818 0.05 -0.01392501526709693 +0.7285720056305425 0.05 0.008823390221310554 +0.6514389276646688 0.05 -0.008829915580547812 +0.5704680991793964 0.05 0.03393932159026841 +0.5727891849537927 0.05 -0.03497298455667183 +0.8815850852272742 0.05 0.03158508522727399 +0.6296921069879045 0.05 -0.03318684863076656 +0.7503119922331667 0.05 0.03298963937466383 +0.8537546825856011 0.05 0.03501049899653612 +0.7933971617061262 0.05 -0.03508663889261566 +0.5997854443809685 0.05 -0.01546236058222145 +0.5402805810719788 0.05 -0.03358823545490575 +0.5167083333333322 0.05 -0.03329166666666675 +0.5167083333333351 0.05 0.03329166666666349 +0.6700000000000035 0.05 -0.03644898499481984 +0.7099999999999986 0.05 0.03644898499482799 +0.5858970762503957 0.05 0.03548103207057865 +0.8158173753851423 0.05 -0.01563685848260959 +0.8065439573075937 0.05 0.03578296097856078 +0.7809288456565462 0.05 0.01590362811629763 +0.6194881975778546 0.05 -0.01623664375634807 +0.7597515527950396 0.05 0.01299999999999832 +0.5397371905308765 0.05 0.03352675153138886 +0.6976317370273817 0.05 0.01401805295064405 +0.6823682629726202 0.05 -0.01401805295064068 +0.6145410079578917 0.05 0.03477100775432014 +0.8853510573533301 0.05 0.01668773594547453 +0.5368587176263018 0.05 -0.004531490926789811 +0.7649648399354227 0.05 -0.0348717572129668 +0.5418528874358606 0.05 0.01331821355916012 +0.6702700270738806 0.05 0.03466962295425119 +0.7097196078852097 0.05 -0.03466408822366616 +0.6316723248465266 0.05 0.03570852545507076 +0.5133445212211802 0.05 -0.01806159386788447 +0.5128053526593139 0.05 0.01891315494406945 +0.8205863283932904 0.05 0.01252552272263671 +0.7482132406485411 0.05 -0.0356525929848879 +0.8851318187553352 0.05 -0.0145784731132428 +0.6120650527196303 0.05 0.01465399990686321 +0.7676178503712103 0.05 -0.01509655793473583 +0.8341148984952726 0.05 0.03633994034479354 +0.8652117549743643 0.05 -0.035692268761461 +0.5627831624864372 0.05 0.01456527432466247 +0.7815255246182127 0.05 -0.01140494842778125 +0.8661312270486357 0.05 0.002797275735740727 +0.7386047031478846 0.05 -0.02098647463013169 +0.6600357243916224 0.05 0.02062500000000432 +0.7199642756083695 0.05 -0.02062499999999493 +0.6413861499610225 0.05 0.02104345293508204 +0.5596333333333297 0.05 -0.01078358208955708 +0.5447397034817949 0.05 -0.01651722081336172 +0.8690049346806932 0.05 0.03782165099106827 +0.8896949404761911 0.05 -0.03969494047619129 +0.3948316869174251 -0.03085156954286597 0.01515402472060502 +0.2600542582660937 0.03070314599563059 0.02179527794111423 +0.2223724300767276 -0.02845553482113928 0.02879787537569797 +0.2456915638346782 0.03341268263249565 -0.009829131358233101 +0.2641507969974554 0.03046874432052893 -0.02609914737024124 +0.4436814136903264 -0.03015445186956119 0.02485903633636872 +0.2330971418182773 0.01495788641300839 0.0007805612859892418 +0.2225450048412211 0.03217393035256785 0.003021555919094606 +0.222551512920568 0.01422414929207251 -0.01578630769347272 +0.3562451635154071 0.03327473009062963 -0.006892350930580571 +0.3672278812261873 0.02776674207274479 -0.02580371255129431 +0.3669511472499333 -0.01176654515295407 -0.03364375611221149 +0.3450558933773214 -0.01944244233605587 -0.03045328091081258 +0.3582282939274034 0.0003007992060837864 -0.01735138978872879 +0.397418750991894 -0.02498556828904953 -0.02951934900116482 +0.44112512194665 0.01027314590921308 -0.01663543102766708 +0.4326067640228854 -0.01397511481067069 -0.03318199818041815 +0.4210789729546389 0.001013112593322699 -0.01594751741303785 +0.2452829422509121 -0.03139630212680766 -0.002885747042376896 +0.4525072767719693 0.02768966464268958 -0.01363666186529361 +0.4463990879211745 0.02911084293979108 -0.03095059227646249 +0.4619827664161339 0.01661084293979108 -0.02603697954343597 +0.3256133728325064 0.02929691473777455 0.02078135758312278 +0.4773950971414889 0.02848876056128499 -0.03266645159547543 +0.4787984657207095 0.02829141628138576 0.0003908981011445413 +0.2592969928981111 -0.01233996360781257 0.03221889229525698 +0.2729837150707364 -0.02665862164558204 0.01135063426579345 +0.2446556218574663 -0.01723413758977135 0.01097134796172527 +0.2627592856249989 -0.01418675374185068 -0.002344308966313279 +0.3623039051247581 -0.02995856068304313 0.02232527961102369 +0.2935558394141632 -0.03293976474272804 0.01783740695012025 +0.3921997607331714 0.01450874331038812 0.01204533472275212 +0.4217726702013884 0.01260235480437062 0.001357596614203995 +0.4228274156157414 -0.001102535535094531 0.01613719999484464 +0.4050691408056205 0.001977268461353305 -0.001779562879712067 +0.4601322495321661 0.02251973910762734 0.0311216024661235 +0.4775375131141625 -0.000221486245602703 0.02791988439599958 +0.4569561633476197 0.005669320651305808 0.02377600605173227 +0.4791925137907959 0.02352566877760095 0.02722827642486318 +0.3481183730497209 0.02611903255138505 0.03110757127592697 +0.4503841659482143 -0.03138285393298516 -0.008595940036554168 +0.4354503522477294 -0.0299399805381366 0.0002178186779485184 +0.3569604198731278 -0.01159558156954918 0.02727007843271138 +0.3446868696702194 -0.01835915044206556 0.0005436969044133611 +0.3707731152819682 -9.030506276698491e-05 0.01739183894971509 +0.3642059326264606 -0.01868327002800025 0.0001030463858824141 +0.3219680005501681 -0.007478710317365642 0.03195690543618204 +0.338444093316967 -0.0005068762539270179 0.01826951793644572 +0.328807477436752 -0.02699107163791345 0.01227999356159843 +0.3148997184155449 -0.01463024267949486 0.001052845258946862 +0.2982242962467802 -0.02440331469027322 -0.02915148772400863 +0.2766085300504845 -0.02890591079518696 -0.02454200597017365 +0.4768289342943234 -0.02909207722389562 -0.03112064593857316 +0.4462408035133477 -0.02951278552327483 -0.02702009350633399 +0.4628232714580323 -0.01318638974175532 -0.02477077278429182 +0.4207395503791213 0.03064598697337794 -0.02713756978038789 +0.2204673052675647 0.02502743926263522 0.02343191110592711 +0.4372630436468146 0.01538707768922584 0.01279720247634408 +0.440521687720639 0.0244412086497263 0.02880073625552781 +0.4188812998817311 0.01463977812574267 0.03132696473748217 +0.4404731095597331 -0.008335281761129897 0.02525196949553914 +0.4155535644193085 -0.03208061397421847 -0.0285696122757891 +0.3998243251265834 0.009822699945029302 -0.0259333285446511 +0.4787984657207092 0.003074643403236483 -0.02828630769347272 +0.3051384541227747 0.02263722700783723 0.03074156446753354 +0.2714230597506788 9.500420934140802e-05 0.01840317495955934 +0.3076563281518794 -0.0004395599525643043 0.01886315680094001 +0.2319204191732372 -0.02807694348271156 -0.03361522117406815 +0.2488880172098366 -1.431850723097e-05 0.01781605192273666 +0.2836523658613085 0.02987842876988243 0.02273048389935295 +0.4124517224309097 -0.03215205233812223 0.02290277572924593 +0.4207232514568481 -0.02148848968781623 0.007789278823513421 +0.443570920507813 -0.01116782232486042 -0.01512058232583507 +0.4421573258071629 0.000177721005686621 0.002375642928163856 +0.2225515129205679 -0.01438822920761239 0.01541988439599956 +0.3877523691579392 0.0309502375644899 -0.03095023756448976 +0.2180151018099789 0.006659015139023476 0.01472118415254999 +0.2858473121682158 0.01833954474215024 -0.0002943705015093986 +0.2561612107066069 0.01551082227790925 -0.002249016979171493 +0.4787664033505582 0.01230347000765726 0.009858460460935187 +0.4626944224579536 0.02489948940545901 0.01318638974175538 +0.4161059372338756 0.02952972543754711 0.01809143488371372 +0.4602033482786541 0.01246921389307103 -0.0004112329020190698 +0.4466824516623362 0.0332933947170635 0.008732048174590841 +0.3379443712005143 -0.003218619828307614 -0.01661604862585584 +0.450286132705612 -0.0004579592481028995 -0.02942486284643481 +0.3508377320066963 0.01910351485747559 -0.0277787471634226 +0.412586727468004 -0.0243160650346851 -0.01026443688589293 +0.3086324608882686 -0.003239619890121218 -0.01955038745456732 +0.2939684786055808 -0.01415482423169363 -0.001848608368396136 +0.3089065127745061 0.02068258053689606 0.0109831105563026 +0.3057301331988262 -0.02255650686974327 0.03017207829813837 +0.3158950158986316 0.03022959442406362 -0.02604698333707986 +0.3781104431455941 0.0117512894499895 -0.02539909852826659 +0.3759542294424479 -0.009768959647303928 -0.01311154577483876 +0.3766119635839648 0.01455698547592367 -0.0008352732487248118 +0.2177612202917451 -0.0003535750385093503 -0.009629992028594617 +0.222551512920568 -0.0154238239374604 -0.01438559152761299 +0.2233659496409063 -0.02398895195460473 0.001705820592999895 +0.2437802590348806 0.02833652580224985 -0.02723683371610015 +0.2200119495002819 0.03347877241201461 -0.02775414017159599 +0.3298644127560415 0.01492644954510664 -0.0280707801842848 +0.478587965395198 -0.02792382393746042 -3.272300755620232e-05 +0.2423958099669676 0.009807069746296245 -0.03126552152872897 +0.3919761901238169 -0.004500147067220396 0.02353091523681001 +0.4187011482230269 -0.01468149099673924 0.03234414562657853 +0.4687870129691857 -0.02105730651144535 0.02045451694884418 +0.3885942247424408 -0.02273310473303257 0.0319424438493334 +0.3353226269221042 -0.02268264022792746 0.03025433008152887 +0.3781550372672844 -0.03010442083463417 -0.01085927149214343 +0.2457305634650344 -0.01742363012430614 -0.02475045588518738 +0.278902165670748 -0.0008458994930925067 -0.01834855759619963 +0.2913655545836993 0.01798896792664747 -0.0223370012603451 +0.3256617218545939 -0.02080413932744975 -0.0291416561881474 +0.323265640922238 0.01129237928202794 0.0273882060752512 +0.3287100411463604 -0.0266999245201418 -0.007067540250903606 +0.3055799365483364 -0.03160580483650437 0.003749868728232268 +0.3975272976079905 0.02983189716513126 0.02516174850709098 +0.3492498457814044 0.01418745476608818 0.01088302287589981 +0.231371240072376 0.007910818122476862 0.02998372804427258 +0.2155000636886625 0.0108837386006035 -0.03182038348401263 +0.2261679158340656 -0.006053015236937147 -0.03090367826071715 +0.3739760598665394 0.03067144173909083 0.0116832806081335 +0.4031485954013059 0.02030736892110031 -0.001997588106003922 +0.3351902393016208 0.03032923191702874 -0.01715734372283922 +0.4791642750725139 0.01249213952043748 -0.01048971757674108 +0.4794218728708617 -0.005466431074023835 0.008775140934339709 +0.4608995136431985 -0.01061396193990583 -0.0002155986641521907 +0.2227135786534258 -0.03377400814141551 -0.01825713952430826 +0.3730734957055963 0.01871605133999222 0.03039539973227738 +0.4766204496400624 -0.01714719322265162 -0.01415636431190479 +0.2419234593322988 0.03008219244821164 0.01285004810829764 +0.3256561875550551 0.0145160158703936 -0.001592993351886007 +0.2563360433445678 0.002390599971017028 -0.01870140512562847 +0.367774621129798 -0.03037813692302638 -0.02718102030760243 +0.4458063711017042 -0.01929305300128 0.01152883863985771 +0.4035348554434861 -0.008961435800101543 -0.01716259907767991 +0.394229978695918 -0.01626818271112888 0.001339849573797625 +0.4347832527032531 0.03316792992241206 -0.01116468884026688 +0.2407653214737369 -0.00859642458423685 0.03157955466176256 +0.3497402024015687 0.01496223111665312 -0.008942951616003033 +0.2482533193293349 -0.02803636380589964 0.02803636380589526 +0.4168114711314486 0.03282610858466346 -0.0039279401480011 +0.2708682716906434 -0.02787386552581961 0.03067178764191068 +0.2335156863916927 -0.004478440125119608 0.004158306798562914 +0.3800787826911248 -0.01623099105948641 0.01602645211675912 +0.23411721800999 -1.920666457122001e-05 -0.01196088873091455 +0.4610804372590023 -0.03064055669085496 0.00668160266478903 +0.7681594691199788 -0.03195757506474774 0.02503691869602563 +0.7480794035113119 -0.02623703073639783 0.02890793855043926 +0.7450937100855599 0.003781940082733049 0.03014248742022632 +0.7208482761344148 -0.0002263755443389248 0.01753326034306292 +0.7367462807465587 -0.01187441646882148 0.01632235078674905 +0.8586866028702915 -0.004710284433408899 -0.03208439678256587 +0.8448945202798681 9.530107594945755e-05 -0.01942463139512358 +0.6598634712980861 -0.02954823872969555 0.02825144762772723 +0.6366493512361078 -0.03192042872392074 0.0257775014075541 +0.6582881930546614 -0.03008733174554527 -0.003300328814070194 +0.6520143388537584 0.009562670364096817 -0.01095812128559598 +0.6341173011821278 0.002046963403908105 -0.007629559098971917 +0.6328114783615987 -0.002709594366240406 -0.02777245716445776 +0.6552945617124296 -0.01030920721273455 -0.01251704742766468 +0.5777230833095841 0.01403952993209623 -0.03037285560176045 +0.5431930691424494 0.00979419266446678 -0.03185426388461106 +0.5466373849049394 0.02828219382980209 -0.0284472170728908 +0.5532119673802942 -0.01035633580580352 0.01509309068900989 +0.5471578916928234 -0.0119918175763743 0.03143914919184035 +0.5374519463457739 6.811017465729353e-05 0.01131110154927638 +0.5255213829211325 -0.02209933664186155 0.02701470143127106 +0.5159469249637603 0.022253797949753 0.02982464823659817 +0.5173575717102875 0.03336343874599759 0.01511080323267845 +0.5408246113418602 -0.03125681146422218 0.02478609381274246 +0.8684934706917383 0.02052164935190312 0.022915774191039 +0.5661352958044656 0.03132315655694554 -0.02155805859135841 +0.5411527547352961 -0.01143266842168032 -0.03121116670422328 +0.5220409268577819 -0.004069434828290515 -0.02688559152761297 +0.5320722697716992 -0.02914103538623778 -0.01771514491740284 +0.5374519463457739 6.811017465730221e-05 -0.01131110154927638 +0.7637066715499302 0.0307078942379137 -0.02301747601056689 +0.781750251662682 0.02517963549581603 -0.02469738879464756 +0.7535820883556668 -0.01173788365996066 -0.02231835362534323 +0.7445988955124107 -0.0005964320479636357 -0.005034058916266487 +0.7461965598786076 -0.01911562023170937 0.001285373464462817 +0.7743766993657046 -0.01612196285038494 0.000941980398991904 +0.7261819934440695 0.02055864585625923 -0.0003026626877499737 +0.6962127959195608 0.02899587744927311 0.02241445501103583 +0.7007722994523797 0.01730166427282456 0.000575307049531501 +0.7061229849604063 0.0128987120614004 0.03186996920127973 +0.846122009276608 0.02561032491550415 0.01510332908055092 +0.7390760478126873 0.003385730051437644 -0.02964634744222308 +0.7062745331035685 -0.01147747470726287 0.02746119525421073 +0.6700151997128986 -0.008678913772490283 0.03018522526224005 +0.698179926639334 -0.02775695454471389 0.02538694103971749 +0.8806135760314568 0.03104288538276485 -0.03185049516371992 +0.8676884368581537 0.01517439636254929 -0.01825339525873589 +0.8797749810631245 0.02996101536872536 0.002984017616987954 +0.5295523594339002 0.01134837396821808 0.03412495323143465 +0.870949635433136 0.0004733929612968706 -0.003847201800035204 +0.8496562624438176 -0.01896433824163721 -0.00563516903357518 +0.879779518125191 -0.02974744047708957 0.003242395071368824 +0.864433410480729 -0.0007296760872861291 0.01288827495136211 +0.7017719149533855 -0.02845482605002425 -0.01781672742897902 +0.6456871915797153 0.02521352432591252 -0.02223198820517282 +0.7225375180257869 0.03157921802541516 -0.01729624358649286 +0.7203356801584447 0.0004080394352027183 -0.01813888415223442 +0.7022227768084933 0.02764100609683854 -0.02498458844404754 +0.5628924909770046 -0.01366615523243859 -0.01775352379076474 +0.544487568879395 -0.03173075431969861 -0.002125036660110555 +0.5472291701156102 -0.02915189236134182 -0.02832955338978987 +0.6700420928882783 0.01870018536516457 -0.001892789313240317 +0.677761382887752 0.0276534371840481 -0.02462469805842989 +0.8827049407145181 0.007221405468357407 0.01869901262464056 +0.8840191613714209 -0.01252400328852233 0.03207072034681712 +0.8032108016810797 -0.01274131338916029 0.02032072419504393 +0.720237937916748 0.02490349536518003 0.02728334605734298 +0.7046036935851496 0.01014483640676661 -0.03316296679448086 +0.8826997780920006 -0.01380161164795255 -0.007649890543149801 +0.8698529380586248 -0.0106203743618878 -0.01870328192234594 +0.8778567073351911 0.006024397857963345 -0.03073208713891962 +0.5708399682144641 0.03078705808175161 0.02646335748933491 +0.6494657753671929 0.03152764991013861 -0.000836645883627567 +0.5364849114892138 0.01378280457477683 9.450809270679806e-05 +0.5558480494165702 0.0002082450666870707 -0.0002036468343302872 +0.7153930661157526 -0.03045564474762537 0.01863506436365715 +0.6724812528077865 0.007103932075328164 -0.02669589846188299 +0.5220409268577819 -0.003033840098442505 0.02791988439599958 +0.5237836907862905 -0.01466487470031796 0.002176472711411769 +0.6202645621089828 0.02417632261357642 -0.02472061616709076 +0.6119430036833632 -0.006490097563559776 -0.03121674043110261 +0.61508185576915 0.0005118637428630345 0.0001862156502199733 +0.7780510526768765 0.03110895587300093 0.01048318489190528 +0.809210789853239 0.02828751840176514 -0.02936483557368365 +0.8005065823384225 0.01682479770221204 -0.0004097233022403431 +0.5778777665910201 -0.02886613504908622 0.0244900494395952 +0.6870552875755976 -0.0006643930778089357 0.01744679212940192 +0.5895281320232338 0.03117964672415486 -0.02501042741115539 +0.6044116628309926 0.02471974476851957 0.005259566895282984 +0.8044350749000226 0.004749974938892674 -0.02440270125783163 +0.8321781722726942 0.01761423040359641 -0.03126515778558214 +0.8299115257087625 -0.01709336423087091 -0.0184049344913407 +0.8754614727560929 -0.03188235076482514 0.0207115088337852 +0.8551535768232991 -0.01554248159171524 0.02572512549766946 +0.7743350412077019 -0.02788570212622034 -0.02543823477932566 +0.7929547112251962 -0.03093596317163277 0.01940727588636911 +0.8176665238353011 -0.02546578960733627 0.02763407945289909 +0.8246341014557088 0.01017160783793477 0.03128991432820236 +0.8247349088900254 0.02993063870735627 0.02224610150774127 +0.5874988148546649 -0.02943311510069084 -0.01794884901484192 +0.5714806634416456 -0.02842132816027689 -0.02847488234273542 +0.7595669640492654 0.02108674027626399 -0.006516138609894507 +0.7559859592663384 0.03056325878410939 0.02103730724126729 +0.6795483424592186 -0.02865062712738153 0.02484666450094491 +0.5254318789450476 0.01429574985001976 -0.01578630769347272 +0.5218691803441412 0.02850397052842932 -0.03149646698268002 +0.6105556986078478 -0.02853417280441497 0.02835347374732809 +0.6133323361590902 -0.01821421308149012 -4.585178213466212e-06 +0.6711676984647563 0.02534079966085444 0.03064546777329857 +0.5649846321807913 0.02806423268043165 -0.0009579230954460186 +0.5390216178412099 0.03337367056330109 -0.01354211420512963 +0.5469247546419853 0.02449045247547684 0.009403487635975082 +0.6670925437949522 0.001462741657739977 0.01145082011062092 +0.7574236527817471 0.01266234919839641 -0.02975509274276328 +0.7616411531278539 -0.03267537166648311 0.003304938964024005 +0.6605269221725747 -0.02774410748165226 -0.02642050801547449 +0.7753132772202709 0.02438977246334956 0.03023843841076033 +0.7254403703414557 -0.02100289921883482 -0.02920753450670315 +0.7314911491814066 -0.02806729721133174 -0.009868622493918483 +0.7137869533946442 -0.0188796436463304 0.0007284155796594485 +0.8156049265533015 -0.03363274945118559 -0.01373971878759263 +0.8349341443978545 -0.03234803409203876 -0.006421989248296718 +0.6840699614630571 0.00121261855492676 -0.001329503015460842 +0.7421089582097642 0.02892309709698912 -0.02352109783048876 +0.8806184115385665 0.01479109003391143 -0.005611341228694728 +0.8369305329302866 -0.02432504659763359 0.0142526588492278 +0.7844750157336963 -0.0002606817362723717 -0.0317262601244707 +0.6390338968860163 -0.03047492608282773 -0.0172832470835409 +0.5167740263468028 0.002014606294388173 0.01217739341903502 +0.8530586026984274 0.02697873187904287 -0.02766626115373952 +0.519072880173046 0.01885141840395588 0.002073657343769185 +0.6411314364022547 0.01014777832680515 0.03185057915577204 +0.6228086710449191 -0.02484502224142999 -0.02827747027239911 +0.6033330083297386 -0.02326797480525727 -0.02881949445698777 +0.5966061176369076 -0.01757393607980125 0.03075121720528029 +0.6418789241919466 -0.009166285589256865 0.03213619915596033 +0.6968282428243516 -0.009135270560509961 -0.02508385389772054 +0.6807424572729808 -0.02676300430103798 -0.0234552827542438 +0.6938106537741657 -0.01639991658791932 -0.002126039189077251 +0.6740545148551176 -0.01563965901876488 0.0003298855185374996 +0.5674689793074995 -0.01355104851466483 0.03054661179781683 +0.8562569800208972 -0.02336388843476635 -0.03463800130754705 +0.8087095183756545 -0.0138413085706558 -0.01413255695300056 +0.8207140875588621 0.01708927131370007 -0.01387948474106386 +0.8153367196830001 0.001081478771077548 3.989816606811198e-05 +0.8770985769918019 -0.02999786166488844 -0.02189384076072546 +0.6628909128043753 0.03153239107082204 0.01269918658941994 +0.5620931387833524 0.01293921494678414 0.03115956731627175 +0.6035200424851344 0.01979677575835807 -0.01511888878256842 +0.5317503355425618 0.0183259023966194 0.01704023562227428 +0.5455990044275285 0.02806738635154583 0.02832955338979003 +0.6343792497498998 -0.01994122025299231 0.002592127722874388 +0.5908428751525497 0.01238604827401068 0.02931448632164319 +0.6002940230989691 -0.001349797101934234 0.01910398276645069 +0.5797595787395357 -0.000565155841889984 0.01745750660781975 +0.5738238290337589 -0.0167505342602122 -9.816863792570471e-05 +0.6220142302051608 0.02022440622680703 0.03152022084630358 +0.5170593586943241 0.0323362659456887 -0.013903178565565 +0.626870357713699 0.0006221088592675844 0.02019091475485538 +0.8409152515483734 0.0210119800064143 -0.007925246993710973 +0.8386137533925937 0.000621050405574146 0.01190938345240662 +0.7539030932291799 -0.03191601025537857 -0.02362794876748736 +0.8613670860846667 0.02830403968694895 0.001555840278179811 +0.6507633205793908 -0.01012018550131773 0.0144772684613528 +0.7806619183631671 0.002243659841762569 0.02219881095187311 +0.835192731653345 -0.03215682144787215 -0.02931677880967898 +0.729625104164114 -0.02556547940405226 0.03076514055966961 +0.7938085628718006 -0.0201381465343187 -0.002301698356843112 +0.63109725468677 0.02033390253197411 0.008532796600685367 +0.6035588257416113 0.02912142831624826 0.02496305996402303 +0.8159668321026832 -0.02323896997682172 -0.03061880833035523 +0.8628462091470214 0.003755349323639562 0.0323659270926975 +0.6001664198484786 -0.0005747167544707626 -0.01695413119482846 +0.8546069819679784 -0.03174196207033602 0.00887557209262772 +0.8015921793737687 0.00862521161449864 0.02611621607658911 +0.5683433978161785 0.01470318864173004 0.01336843516797812 +0.5866195144008053 0.01844880230877272 -0.0006701837556251644 +0.5888482413493634 -0.03471191792132866 0.009328486733565173 +0.562106104562095 -0.03179089947961437 0.01502991996049625 +0.5529452487041049 0.01757080606501167 -0.01333045153364713 +0.5797236994761362 -0.0003761506919971413 -0.01764987883838145 +0.7534233380458358 -0.001600993977452007 0.01316718599820998 +0.7406469423171664 0.02076511679931237 0.01269671866406634 +0.8816586579267978 -0.01308409221004672 0.01424925958857053 +0.6371749657445407 0.03281993382542166 0.02831721977685838 +0.5930486719886338 -0.01726109314182077 -5.006690288923352e-05 +0.7855107620986597 -0.0006871894783808822 -0.01050119267183438 +0.767003812188231 0.002617860145428148 -0.01574911503927285 +0.740485387167102 0.02463570369190349 0.03484054795784225 +0.6507633205793908 0.01487981449868227 0.0144772684613528 +0.829568172438586 -0.009150721259876078 0.03167546542570399 +0.7921479587903116 -0.03193963975963156 -0.03240160236607499 +0.7813216054496637 0.01503755920155474 0.0009554752393387787 +0.8210225806300648 -0.01770775155266638 0.001618435671884324 +0.7966224639492462 0.03152808180312228 0.02968572527545733 +0.7746590802598589 0.03422074932330175 -0.008276380795422351 + +CELLS 7206 33940 +3 206 208 199 +3 197 206 193 +3 199 208 195 +3 200 205 194 +3 198 207 196 +3 205 206 197 +3 198 208 207 +3 200 207 205 +3 18 199 17 +3 25 197 26 +3 14 198 13 +3 21 200 22 +3 2 202 19 +3 27 202 2 +3 23 201 3 +3 3 201 24 +3 12 204 1 +3 1 204 20 +3 16 203 0 +3 0 203 15 +3 200 216 22 +3 18 215 199 +3 197 211 26 +3 193 211 197 +3 197 209 194 +3 14 214 198 +3 198 212 13 +3 199 215 193 +3 194 216 200 +3 25 209 197 +3 198 214 195 +3 199 210 17 +3 195 210 199 +3 196 212 198 +3 200 213 196 +3 21 213 200 +3 194 205 197 +3 192 208 206 +3 192 206 205 +3 193 206 199 +3 196 207 200 +3 195 208 198 +3 207 208 192 +3 205 207 192 +3 24 209 25 +3 19 215 18 +3 13 212 12 +3 22 216 23 +3 26 211 27 +3 17 210 16 +3 15 214 14 +3 20 213 21 +3 202 215 19 +3 201 209 24 +3 23 216 201 +3 27 211 202 +3 12 212 204 +3 16 210 203 +3 203 214 15 +3 204 213 20 +3 194 209 201 +3 196 213 204 +3 202 211 193 +3 201 216 194 +3 203 210 195 +3 193 215 202 +3 204 212 196 +3 195 214 203 +3 240 218 280 +3 53 52 235 +3 34 35 234 +3 218 240 274 +3 241 39 284 +3 57 240 285 +3 39 40 284 +3 58 57 285 +3 239 225 273 +3 231 240 280 +3 230 243 286 +3 225 239 256 +3 243 280 286 +3 220 239 273 +3 34 234 248 +3 234 35 259 +3 53 235 260 +3 235 52 254 +3 240 226 274 +3 13 14 242 +3 244 232 297 +3 233 245 298 +3 239 55 256 +3 37 238 255 +3 278 244 297 +3 245 279 298 +3 239 220 287 +3 44 43 243 +3 217 246 282 +3 246 217 283 +3 29 30 245 +3 48 47 244 +3 55 239 269 +3 238 37 270 +3 217 281 283 +3 262 59 285 +3 41 261 284 +3 240 57 258 +3 39 241 257 +3 226 240 258 +3 241 227 257 +3 240 231 285 +3 227 241 276 +3 281 237 283 +3 249 227 276 +3 274 249 276 +3 250 224 277 +3 51 251 254 +3 273 250 277 +3 59 58 285 +3 40 41 284 +3 5 59 262 +3 42 5 262 +3 41 4 261 +3 4 45 261 +3 245 30 295 +3 48 244 296 +3 13 242 293 +3 242 14 294 +3 219 263 271 +3 33 248 252 +3 30 31 295 +3 49 48 296 +3 293 242 297 +3 242 294 298 +3 33 34 248 +3 55 54 256 +3 36 37 255 +3 251 223 254 +3 31 264 295 +3 265 49 296 +3 217 247 281 +3 52 51 254 +3 263 234 271 +3 248 222 252 +3 247 222 253 +3 223 247 253 +3 0 28 267 +3 15 0 267 +3 46 1 268 +3 1 12 268 +3 44 243 289 +3 243 43 290 +3 243 230 289 +3 231 243 290 +3 232 293 297 +3 294 233 298 +3 35 36 259 +3 54 53 260 +3 36 255 259 +3 256 54 260 +3 51 50 251 +3 32 33 252 +3 270 227 288 +3 226 269 287 +3 275 217 282 +3 243 231 280 +3 246 228 282 +3 229 246 283 +3 266 219 272 +3 269 239 287 +3 238 270 288 +3 236 275 282 +3 280 218 286 +3 232 244 291 +3 244 47 291 +3 29 245 292 +3 245 233 292 +3 37 38 270 +3 56 55 269 +3 235 266 272 +3 219 253 263 +3 251 50 299 +3 32 252 300 +3 237 251 299 +3 225 260 272 +3 260 235 272 +3 259 224 271 +3 234 259 271 +3 245 228 279 +3 229 244 278 +3 252 236 300 +3 246 221 279 +3 228 246 279 +3 221 246 278 +3 246 229 278 +3 247 217 275 +3 252 222 275 +3 236 252 275 +3 228 245 295 +3 244 229 296 +3 231 262 285 +3 261 230 284 +3 224 255 277 +3 255 238 277 +3 38 39 257 +3 57 56 258 +3 253 219 266 +3 255 224 259 +3 225 256 260 +3 220 277 288 +3 222 248 263 +3 248 234 263 +3 235 254 266 +3 254 223 266 +3 43 42 290 +3 45 44 289 +3 277 238 288 +3 241 284 286 +3 284 230 286 +3 237 265 283 +3 265 229 283 +3 228 264 282 +3 264 236 282 +3 257 227 270 +3 226 258 269 +3 251 237 281 +3 223 251 281 +3 222 247 275 +3 253 222 263 +3 224 250 271 +3 250 225 272 +3 250 219 271 +3 219 250 272 +3 226 249 274 +3 225 250 273 +3 28 29 292 +3 14 15 294 +3 47 46 291 +3 12 13 293 +3 247 223 281 +3 249 220 288 +3 220 249 287 +3 221 278 297 +3 279 221 298 +3 218 274 276 +3 220 273 277 +3 223 253 266 +3 227 249 288 +3 249 226 287 +3 31 32 300 +3 50 49 299 +3 42 262 290 +3 261 45 289 +3 38 257 270 +3 258 56 269 +3 276 241 286 +3 218 276 286 +3 230 261 289 +3 262 231 290 +3 267 28 292 +3 15 267 294 +3 46 268 291 +3 268 12 293 +3 297 242 298 +3 221 297 298 +3 264 228 295 +3 229 265 296 +3 232 268 293 +3 268 232 291 +3 267 233 294 +3 233 267 292 +3 264 31 300 +3 49 265 299 +3 265 237 299 +3 236 264 300 +3 319 301 332 +3 320 303 357 +3 317 302 334 +3 303 320 335 +3 301 319 358 +3 321 353 360 +3 302 317 356 +3 356 324 360 +3 313 324 356 +3 353 302 360 +3 39 321 362 +3 314 321 360 +3 40 39 362 +3 330 35 364 +3 63 64 322 +3 32 333 366 +3 36 35 330 +3 320 330 364 +3 17 18 323 +3 315 327 374 +3 326 316 375 +3 355 326 375 +3 327 354 374 +3 330 320 357 +3 32 31 333 +3 336 301 358 +3 333 319 366 +3 301 336 361 +3 76 75 324 +3 30 29 326 +3 61 62 327 +3 71 337 365 +3 63 322 349 +3 319 333 358 +3 345 41 362 +3 322 312 349 +3 327 62 349 +3 30 326 348 +3 321 314 362 +3 310 322 347 +3 322 64 347 +3 321 39 342 +3 307 321 342 +3 71 72 337 +3 321 307 353 +3 334 307 341 +3 305 334 341 +3 335 306 340 +3 308 335 340 +3 41 40 362 +3 312 322 361 +3 322 310 359 +3 337 317 365 +3 310 339 340 +3 339 308 340 +3 307 338 341 +3 338 309 341 +3 312 327 349 +3 326 311 348 +3 69 70 328 +3 4 41 345 +3 74 4 345 +3 34 33 329 +3 73 6 344 +3 6 77 344 +3 17 323 372 +3 323 18 373 +3 317 337 356 +3 319 332 378 +3 331 318 377 +3 318 331 380 +3 38 37 338 +3 65 66 339 +3 323 373 374 +3 372 323 375 +3 311 336 358 +3 28 0 351 +3 0 16 351 +3 2 60 352 +3 19 2 352 +3 76 324 369 +3 324 313 369 +3 324 75 368 +3 314 324 368 +3 373 315 374 +3 316 372 375 +3 336 312 361 +3 38 338 342 +3 302 356 360 +3 332 310 340 +3 309 331 341 +3 306 332 340 +3 331 305 341 +3 325 67 381 +3 67 325 343 +3 324 314 360 +3 34 329 364 +3 328 70 365 +3 69 328 363 +3 329 33 366 +3 335 320 376 +3 317 334 379 +3 338 307 342 +3 332 306 378 +3 305 331 377 +3 331 303 380 +3 325 308 343 +3 306 335 376 +3 334 305 379 +3 308 325 350 +3 325 318 380 +3 318 325 381 +3 331 309 357 +3 303 331 357 +3 339 66 343 +3 316 326 371 +3 327 315 370 +3 326 29 371 +3 61 327 370 +3 310 332 359 +3 332 301 359 +3 339 310 347 +3 65 339 347 +3 309 338 346 +3 338 37 346 +3 328 365 379 +3 329 366 378 +3 364 329 376 +3 363 328 377 +3 314 345 362 +3 67 68 381 +3 308 339 343 +3 327 312 354 +3 311 326 355 +3 336 304 354 +3 312 336 354 +3 304 336 355 +3 336 311 355 +3 66 67 343 +3 36 330 346 +3 330 309 346 +3 303 335 350 +3 335 308 350 +3 333 31 348 +3 311 333 348 +3 39 38 342 +3 334 302 353 +3 307 334 353 +3 309 330 357 +3 333 311 358 +3 75 74 368 +3 72 73 367 +3 77 76 369 +3 37 36 346 +3 64 65 347 +3 337 313 356 +3 31 30 348 +3 62 63 349 +3 337 72 367 +3 313 337 367 +3 29 28 371 +3 60 61 370 +3 16 17 372 +3 18 19 373 +3 304 355 375 +3 354 304 374 +3 68 69 363 +3 35 34 364 +3 70 71 365 +3 33 32 366 +3 365 317 379 +3 366 319 378 +3 318 363 377 +3 320 364 376 +3 376 329 378 +3 306 376 378 +3 377 328 379 +3 305 377 379 +3 74 345 368 +3 344 77 369 +3 73 344 367 +3 322 359 361 +3 359 301 361 +3 350 325 380 +3 345 314 368 +3 313 344 369 +3 344 313 367 +3 352 60 370 +3 28 351 371 +3 351 16 372 +3 19 352 373 +3 374 304 375 +3 323 374 375 +3 352 315 373 +3 315 352 370 +3 316 351 372 +3 351 316 371 +3 363 318 381 +3 303 350 380 +3 68 363 381 +3 396 398 389 +3 387 396 383 +3 389 398 385 +3 390 395 384 +3 388 397 386 +3 395 396 387 +3 388 398 397 +3 390 397 395 +3 76 389 75 +3 83 387 84 +3 44 388 43 +3 79 390 80 +3 6 392 77 +3 85 392 6 +3 81 391 7 +3 7 391 82 +3 42 394 5 +3 5 394 78 +3 74 393 4 +3 4 393 45 +3 390 406 80 +3 76 405 389 +3 387 401 84 +3 383 401 387 +3 387 399 384 +3 44 404 388 +3 388 402 43 +3 389 405 383 +3 384 406 390 +3 83 399 387 +3 388 404 385 +3 389 400 75 +3 385 400 389 +3 386 402 388 +3 390 403 386 +3 79 403 390 +3 384 395 387 +3 382 398 396 +3 382 396 395 +3 383 396 389 +3 386 397 390 +3 385 398 388 +3 397 398 382 +3 395 397 382 +3 82 399 83 +3 77 405 76 +3 43 402 42 +3 80 406 81 +3 84 401 85 +3 75 400 74 +3 45 404 44 +3 78 403 79 +3 392 405 77 +3 391 399 82 +3 81 406 391 +3 85 401 392 +3 42 402 394 +3 74 400 393 +3 393 404 45 +3 394 403 78 +3 384 399 391 +3 386 403 394 +3 392 401 383 +3 391 406 384 +3 393 400 385 +3 383 405 392 +3 394 402 386 +3 385 404 393 +3 53 424 52 +3 92 425 93 +3 468 470 431 +3 57 474 430 +3 431 475 97 +3 58 474 57 +3 97 475 98 +3 414 463 428 +3 431 470 420 +3 433 476 421 +3 428 446 414 +3 470 476 433 +3 53 447 424 +3 425 448 93 +3 428 463 410 +3 424 438 52 +3 408 470 468 +3 92 444 425 +3 410 477 428 +3 21 432 22 +3 422 487 434 +3 435 488 423 +3 55 446 428 +3 429 445 95 +3 434 487 467 +3 466 488 435 +3 447 461 424 +3 425 462 448 +3 80 433 79 +3 436 473 407 +3 407 472 436 +3 87 434 88 +3 48 435 47 +3 428 459 55 +3 95 460 429 +3 471 472 407 +3 416 461 447 +3 448 462 417 +3 99 475 451 +3 452 474 59 +3 420 475 431 +3 426 472 471 +3 97 449 431 +3 430 450 57 +3 415 465 439 +3 441 444 91 +3 439 465 463 +3 98 475 99 +3 59 474 58 +3 5 452 59 +3 78 452 5 +3 99 451 7 +3 7 451 81 +3 434 486 88 +3 48 485 435 +3 21 483 432 +3 432 484 22 +3 453 461 409 +3 438 442 51 +3 49 485 48 +3 88 486 89 +3 417 478 460 +3 459 477 416 +3 449 468 431 +3 430 469 450 +3 415 468 449 +3 450 469 414 +3 432 487 484 +3 483 488 432 +3 52 438 51 +3 56 446 55 +3 95 445 96 +3 413 444 441 +3 455 485 49 +3 89 486 454 +3 437 471 407 +3 91 444 92 +3 424 461 453 +3 412 442 438 +3 412 443 437 +3 437 443 413 +3 46 457 1 +3 1 457 20 +3 3 458 86 +3 23 458 3 +3 80 480 433 +3 433 480 420 +3 433 479 79 +3 421 479 433 +3 484 487 422 +3 423 488 483 +3 460 478 429 +3 428 477 459 +3 90 441 91 +3 51 442 50 +3 407 473 464 +3 420 470 433 +3 418 473 436 +3 436 472 419 +3 409 462 456 +3 464 473 427 +3 408 476 470 +3 434 481 422 +3 423 482 435 +3 435 482 47 +3 87 481 434 +3 55 459 54 +3 94 460 95 +3 456 462 425 +3 443 453 409 +3 90 490 441 +3 57 450 56 +3 96 449 97 +3 442 491 50 +3 417 489 440 +3 440 489 416 +3 441 490 426 +3 418 466 435 +3 434 467 419 +3 427 491 442 +3 436 467 411 +3 436 466 418 +3 411 466 436 +3 419 467 436 +3 407 464 437 +3 412 464 442 +3 442 464 427 +3 435 485 418 +3 419 486 434 +3 451 475 420 +3 421 474 452 +3 445 465 415 +3 429 465 445 +3 93 448 94 +3 54 447 53 +3 409 456 443 +3 462 489 417 +3 416 489 461 +3 438 453 412 +3 424 453 438 +3 444 456 425 +3 413 456 444 +3 79 479 78 +3 81 480 80 +3 56 450 446 +3 445 449 96 +3 474 476 430 +3 421 476 474 +3 419 472 454 +3 455 473 418 +3 454 472 426 +3 427 473 455 +3 417 460 448 +3 447 459 416 +3 426 471 441 +3 441 471 413 +3 437 464 412 +3 412 453 443 +3 439 463 414 +3 47 482 46 +3 86 481 87 +3 20 483 21 +3 22 484 23 +3 439 468 415 +3 414 469 439 +3 413 471 437 +3 408 468 439 +3 439 469 408 +3 465 478 410 +3 416 477 440 +3 429 478 465 +3 440 478 417 +3 467 487 411 +3 411 488 466 +3 463 465 410 +3 443 456 413 +3 440 477 410 +3 410 478 440 +3 446 450 414 +3 415 449 445 +3 50 491 49 +3 89 490 90 +3 78 479 452 +3 451 480 81 +3 448 460 94 +3 54 459 447 +3 469 476 408 +3 430 476 469 +3 452 479 421 +3 420 480 451 +3 458 481 86 +3 46 482 457 +3 457 483 20 +3 23 484 458 +3 487 488 411 +3 432 488 487 +3 418 485 455 +3 454 486 419 +3 458 484 422 +3 422 481 458 +3 423 483 457 +3 457 482 423 +3 409 489 462 +3 461 489 409 +3 49 491 455 +3 454 490 89 +3 426 490 454 +3 455 491 427 +3 510 523 492 +3 511 548 494 +3 494 526 511 +3 508 525 493 +3 492 549 510 +3 512 551 544 +3 493 547 508 +3 547 551 515 +3 505 547 515 +3 544 551 493 +3 97 553 512 +3 504 551 512 +3 98 553 97 +3 521 556 93 +3 63 513 64 +3 90 557 524 +3 94 521 93 +3 511 556 521 +3 25 514 26 +3 518 565 506 +3 507 566 517 +3 545 565 518 +3 517 566 546 +3 521 548 511 +3 90 524 89 +3 527 549 492 +3 524 557 510 +3 492 552 527 +3 84 515 83 +3 61 517 62 +3 88 518 87 +3 71 554 528 +3 63 539 513 +3 510 549 524 +3 535 553 99 +3 513 539 502 +3 517 539 62 +3 88 540 518 +3 512 553 504 +3 501 538 513 +3 513 538 64 +3 512 533 97 +3 499 533 512 +3 71 528 72 +3 512 544 499 +3 525 532 499 +3 496 532 525 +3 498 531 526 +3 526 531 497 +3 99 553 98 +3 502 552 513 +3 513 550 501 +3 528 554 508 +3 501 531 530 +3 530 531 498 +3 499 532 529 +3 529 532 500 +3 518 540 503 +3 502 539 517 +3 69 519 70 +3 92 520 91 +3 7 535 99 +3 73 536 6 +3 82 535 7 +3 6 536 85 +3 25 563 514 +3 514 564 26 +3 508 547 528 +3 510 570 523 +3 522 567 509 +3 509 571 522 +3 96 529 95 +3 65 530 66 +3 563 565 514 +3 514 566 564 +3 503 549 527 +3 2 542 60 +3 27 542 2 +3 86 543 3 +3 3 543 24 +3 504 559 515 +3 515 559 83 +3 515 560 505 +3 84 560 515 +3 506 565 563 +3 564 566 507 +3 527 552 502 +3 96 533 529 +3 493 551 547 +3 522 532 496 +3 500 532 522 +3 523 531 501 +3 497 531 523 +3 516 572 67 +3 67 534 516 +3 515 551 504 +3 92 556 520 +3 519 554 70 +3 69 555 519 +3 520 557 91 +3 526 569 511 +3 508 568 525 +3 529 533 499 +3 496 567 522 +3 523 570 497 +3 522 571 494 +3 516 534 498 +3 525 568 496 +3 497 569 526 +3 498 541 516 +3 516 571 509 +3 509 572 516 +3 522 548 500 +3 494 548 522 +3 530 534 66 +3 506 561 518 +3 518 561 87 +3 61 562 517 +3 517 562 507 +3 501 550 523 +3 523 550 492 +3 530 538 501 +3 65 538 530 +3 500 537 529 +3 529 537 95 +3 556 569 520 +3 520 570 557 +3 519 568 554 +3 555 567 519 +3 504 553 535 +3 67 572 68 +3 498 534 530 +3 503 545 518 +3 517 546 502 +3 495 545 527 +3 527 545 503 +3 527 546 495 +3 502 546 527 +3 66 534 67 +3 94 537 521 +3 521 537 500 +3 494 541 526 +3 526 541 498 +3 503 540 524 +3 524 540 89 +3 97 533 96 +3 499 544 525 +3 525 544 493 +3 500 548 521 +3 524 549 503 +3 72 558 73 +3 85 560 84 +3 83 559 82 +3 95 537 94 +3 64 538 65 +3 528 547 505 +3 62 539 63 +3 89 540 88 +3 528 558 72 +3 505 558 528 +3 60 562 61 +3 26 564 27 +3 87 561 86 +3 24 563 25 +3 546 566 495 +3 495 565 545 +3 68 555 69 +3 70 554 71 +3 93 556 92 +3 91 557 90 +3 557 570 510 +3 511 569 556 +3 554 568 508 +3 509 567 555 +3 496 568 567 +3 567 568 519 +3 569 570 520 +3 497 570 569 +3 73 558 536 +3 536 560 85 +3 82 559 535 +3 550 552 492 +3 513 552 550 +3 541 571 516 +3 505 560 536 +3 536 558 505 +3 535 559 504 +3 542 562 60 +3 27 564 542 +3 86 561 543 +3 543 563 24 +3 565 566 514 +3 495 566 565 +3 506 563 543 +3 543 561 506 +3 542 564 507 +3 507 562 542 +3 555 572 509 +3 494 571 541 +3 68 572 555 +3 104 105 597 +3 584 603 620 +3 620 603 667 +3 585 596 608 +3 634 123 636 +3 598 116 626 +3 596 573 608 +3 573 596 646 +3 617 136 641 +3 618 107 640 +3 102 602 647 +3 124 123 634 +3 601 125 634 +3 596 585 633 +3 606 591 657 +3 651 606 657 +3 575 620 667 +3 597 105 632 +3 104 597 619 +3 635 100 647 +3 9 141 631 +3 119 9 631 +3 589 617 641 +3 588 618 640 +3 101 102 647 +3 125 601 630 +3 598 580 665 +3 580 598 626 +3 116 598 638 +3 116 117 626 +3 100 101 647 +3 602 102 629 +3 601 582 630 +3 582 601 678 +3 125 124 634 +3 43 44 606 +3 596 614 646 +3 633 139 673 +3 140 139 633 +3 597 632 644 +3 603 132 649 +3 582 604 648 +3 132 603 639 +3 576 642 644 +3 121 120 607 +3 603 584 639 +3 579 616 627 +3 616 586 627 +3 578 615 628 +3 615 587 628 +3 586 617 627 +3 617 589 627 +3 587 618 628 +3 618 588 628 +3 605 111 655 +3 127 604 654 +3 594 612 667 +3 595 613 669 +3 590 634 636 +3 111 605 637 +3 632 587 644 +3 605 581 637 +3 642 597 644 +3 123 5 636 +3 5 42 636 +3 130 129 610 +3 113 114 611 +3 4 100 635 +3 45 4 635 +3 581 605 680 +3 604 582 671 +3 604 127 648 +3 107 108 640 +3 136 135 641 +3 612 575 667 +3 613 577 669 +3 616 593 666 +3 609 580 626 +3 615 592 668 +3 573 616 666 +3 613 595 676 +3 612 594 674 +3 103 104 619 +3 106 107 618 +3 137 136 617 +3 576 615 668 +3 103 619 629 +3 580 608 665 +3 607 580 664 +3 584 620 624 +3 620 581 624 +3 621 582 623 +3 583 621 623 +3 591 606 660 +3 606 44 660 +3 43 606 661 +3 606 590 661 +3 126 125 630 +3 591 635 647 +3 585 608 672 +3 106 618 632 +3 612 578 628 +3 588 612 628 +3 613 579 627 +3 589 613 627 +3 645 575 652 +3 609 122 664 +3 596 633 673 +3 580 609 664 +3 109 110 622 +3 619 583 629 +3 590 606 651 +3 130 610 659 +3 611 114 658 +3 592 615 677 +3 593 616 675 +3 618 587 632 +3 578 612 674 +3 579 613 676 +3 610 129 663 +3 113 611 662 +3 576 621 642 +3 614 138 643 +3 630 582 648 +3 111 112 655 +3 128 127 654 +3 122 121 664 +3 600 645 652 +3 132 131 649 +3 616 579 675 +3 615 578 677 +3 577 653 656 +3 102 103 629 +3 134 133 625 +3 115 116 638 +3 110 111 637 +3 599 625 656 +3 120 119 650 +3 133 132 639 +3 138 614 673 +3 121 607 664 +3 138 137 643 +3 574 657 670 +3 659 610 674 +3 611 658 675 +3 585 607 650 +3 580 607 672 +3 575 612 652 +3 612 588 652 +3 613 589 653 +3 577 613 653 +3 574 651 657 +3 607 120 650 +3 607 585 672 +3 622 600 682 +3 109 622 682 +3 625 599 681 +3 581 622 637 +3 625 584 656 +3 608 580 672 +3 600 622 645 +3 622 581 645 +3 620 575 645 +3 615 576 644 +3 587 615 644 +3 629 583 670 +3 602 629 670 +3 623 582 678 +3 139 138 673 +3 616 573 646 +3 586 616 646 +3 610 663 677 +3 662 611 676 +3 119 631 650 +3 585 631 683 +3 653 599 656 +3 608 573 665 +3 105 106 632 +3 609 626 685 +3 137 617 643 +3 633 585 683 +3 134 625 681 +3 584 625 639 +3 122 609 684 +3 586 614 643 +3 614 586 646 +3 583 619 642 +3 621 583 642 +3 127 126 648 +3 624 577 656 +3 617 586 643 +3 641 599 653 +3 640 600 652 +3 589 641 653 +3 588 640 652 +3 623 574 670 +3 614 596 673 +3 657 602 670 +3 42 43 661 +3 44 45 660 +3 622 110 637 +3 582 621 671 +3 574 678 679 +3 619 597 642 +3 581 620 645 +3 624 581 680 +3 129 128 663 +3 112 113 662 +3 625 133 639 +3 591 647 657 +3 647 602 657 +3 621 576 671 +3 114 115 658 +3 131 130 659 +3 605 655 669 +3 655 595 669 +3 654 604 668 +3 592 654 668 +3 603 649 667 +3 649 594 667 +3 651 574 679 +3 638 598 666 +3 593 638 666 +3 594 659 674 +3 658 593 675 +3 8 122 684 +3 118 8 684 +3 675 579 676 +3 611 675 676 +3 578 674 677 +3 674 610 677 +3 141 140 683 +3 108 109 682 +3 135 134 681 +3 117 118 685 +3 584 624 656 +3 126 630 648 +3 577 624 680 +3 663 592 677 +3 595 662 676 +3 631 585 650 +3 636 42 661 +3 45 635 660 +3 583 623 670 +3 574 623 678 +3 115 638 658 +3 638 593 658 +3 626 117 685 +3 684 609 685 +3 118 684 685 +3 678 601 679 +3 631 141 683 +3 635 591 660 +3 590 636 661 +3 649 131 659 +3 594 649 659 +3 655 112 662 +3 128 654 663 +3 576 668 671 +3 140 633 683 +3 595 655 662 +3 654 592 663 +3 665 573 666 +3 598 665 666 +3 669 577 680 +3 634 590 679 +3 601 634 679 +3 600 640 682 +3 640 108 682 +3 599 641 681 +3 641 135 681 +3 590 651 679 +3 668 604 671 +3 605 669 680 +3 713 696 734 +3 688 713 734 +3 142 750 752 +3 157 158 710 +3 154 155 712 +3 146 147 711 +3 142 143 750 +3 719 763 767 +3 719 703 763 +3 698 709 721 +3 751 100 753 +3 709 686 721 +3 101 100 751 +3 710 158 722 +3 686 709 778 +3 714 102 751 +3 144 713 750 +3 150 151 715 +3 709 698 749 +3 726 707 756 +3 706 727 756 +3 154 712 747 +3 711 147 748 +3 687 726 756 +3 727 687 756 +3 713 688 763 +3 749 116 770 +3 712 155 732 +3 8 118 744 +3 161 8 744 +3 157 710 739 +3 146 711 738 +3 713 144 745 +3 740 686 761 +3 710 740 761 +3 102 714 743 +3 696 713 745 +3 102 101 751 +3 709 718 778 +3 75 76 719 +3 732 156 739 +3 143 144 750 +3 709 749 770 +3 113 717 746 +3 750 703 752 +3 715 701 754 +3 150 715 754 +3 715 151 755 +3 702 715 755 +3 117 116 749 +3 747 712 759 +3 711 748 758 +3 701 715 764 +3 715 702 765 +3 695 716 762 +3 757 690 759 +3 163 162 720 +3 694 718 782 +3 699 729 741 +3 729 692 741 +3 691 728 742 +3 728 700 742 +3 688 783 790 +3 158 159 722 +3 730 699 741 +3 731 701 742 +3 702 730 741 +3 700 731 742 +3 104 716 768 +3 717 113 769 +3 704 751 753 +3 697 732 739 +3 699 747 759 +3 748 700 758 +3 712 757 759 +3 717 694 746 +3 107 106 724 +3 100 4 753 +3 4 74 753 +3 111 110 725 +3 6 142 752 +3 77 6 752 +3 716 695 791 +3 694 717 784 +3 716 104 762 +3 783 714 790 +3 728 705 779 +3 708 729 780 +3 746 694 782 +3 114 113 746 +3 707 726 788 +3 727 706 786 +3 155 156 732 +3 718 694 778 +3 148 149 731 +3 152 153 730 +3 689 728 779 +3 729 690 780 +3 693 721 740 +3 763 688 767 +3 156 157 739 +3 145 146 738 +3 722 693 740 +3 720 693 777 +3 693 722 781 +3 694 733 736 +3 733 697 736 +3 695 734 735 +3 734 696 735 +3 723 693 781 +3 144 145 745 +3 703 719 773 +3 719 76 773 +3 719 704 774 +3 75 719 774 +3 103 102 743 +3 721 686 740 +3 115 718 770 +3 698 721 785 +3 730 153 747 +3 148 731 748 +3 701 727 742 +3 727 691 742 +3 726 702 741 +3 692 726 741 +3 723 164 777 +3 693 723 777 +3 758 689 760 +3 718 709 770 +3 718 115 782 +3 704 719 767 +3 710 722 740 +3 107 724 771 +3 725 110 772 +3 705 728 789 +3 729 708 787 +3 699 730 747 +3 731 700 748 +3 726 692 788 +3 691 727 786 +3 145 738 745 +3 111 725 775 +3 724 106 776 +3 733 690 757 +3 160 723 781 +3 743 695 762 +3 105 104 768 +3 113 112 769 +3 711 758 760 +3 164 163 777 +3 109 108 737 +3 692 729 787 +3 728 691 789 +3 162 161 766 +3 727 701 764 +3 687 727 764 +3 726 687 765 +3 702 726 765 +3 163 720 777 +3 701 731 754 +3 731 149 754 +3 152 730 755 +3 730 702 755 +3 771 724 786 +3 725 772 788 +3 698 720 766 +3 693 720 785 +3 720 162 766 +3 159 160 781 +3 720 698 785 +3 721 693 785 +3 728 689 758 +3 729 699 759 +3 690 729 759 +3 700 728 758 +3 694 736 778 +3 775 725 787 +3 724 776 789 +3 161 744 766 +3 695 743 783 +3 743 714 783 +3 738 696 745 +3 698 744 792 +3 688 734 783 +3 706 737 771 +3 737 108 771 +3 737 707 772 +3 109 737 772 +3 147 148 748 +3 153 154 747 +3 749 698 792 +3 164 723 793 +3 723 160 793 +3 722 159 781 +3 116 115 770 +3 689 735 760 +3 686 736 761 +3 732 697 757 +3 697 733 757 +3 104 103 762 +3 74 75 774 +3 76 77 773 +3 697 739 761 +3 739 710 761 +3 696 738 760 +3 738 711 760 +3 149 150 754 +3 151 152 755 +3 733 694 784 +3 712 732 757 +3 695 735 791 +3 737 706 756 +3 707 737 756 +3 106 105 776 +3 112 111 775 +3 115 114 782 +3 690 733 784 +3 108 107 771 +3 110 109 772 +3 735 696 760 +3 736 697 761 +3 769 708 780 +3 768 716 779 +3 717 769 780 +3 705 768 779 +3 767 688 790 +3 772 707 788 +3 706 771 786 +3 10 164 793 +3 160 10 793 +3 692 787 788 +3 787 725 788 +3 691 786 789 +3 786 724 789 +3 118 117 792 +3 734 695 783 +3 103 743 762 +3 735 689 791 +3 708 775 787 +3 776 705 789 +3 744 698 766 +3 703 750 763 +3 750 713 763 +3 736 686 778 +3 753 74 774 +3 77 752 773 +3 687 764 765 +3 764 715 765 +3 114 746 782 +3 744 118 792 +3 752 703 773 +3 704 753 774 +3 105 768 776 +3 769 112 775 +3 780 690 784 +3 117 749 792 +3 708 769 775 +3 768 705 776 +3 689 779 791 +3 751 704 790 +3 714 751 790 +3 704 767 790 +3 717 780 784 +3 779 716 791 +3 796 808 799 +3 799 808 807 +3 170 799 171 +3 163 801 162 +3 166 802 167 +3 121 800 120 +3 800 818 797 +3 801 819 798 +3 809 818 800 +3 798 819 809 +3 168 804 11 +3 11 804 169 +3 10 803 164 +3 172 803 10 +3 119 805 9 +3 9 805 165 +3 8 806 122 +3 161 806 8 +3 795 819 801 +3 802 817 167 +3 163 816 801 +3 799 811 171 +3 170 810 799 +3 795 811 799 +3 799 810 796 +3 800 814 120 +3 121 815 800 +3 801 816 795 +3 797 814 800 +3 801 813 162 +3 800 815 798 +3 798 813 801 +3 166 812 802 +3 802 812 797 +3 796 817 802 +3 797 818 802 +3 799 807 795 +3 802 808 796 +3 807 808 794 +3 798 809 800 +3 169 810 170 +3 167 817 168 +3 171 811 172 +3 120 814 119 +3 164 816 163 +3 165 812 166 +3 122 815 121 +3 162 813 161 +3 794 818 809 +3 807 819 795 +3 802 818 808 +3 809 819 794 +3 804 810 169 +3 168 817 804 +3 172 811 803 +3 803 816 164 +3 119 814 805 +3 805 812 165 +3 806 815 122 +3 161 813 806 +3 796 810 804 +3 803 811 795 +3 806 813 798 +3 805 814 797 +3 798 815 806 +3 804 817 796 +3 795 816 803 +3 797 812 805 +3 808 818 794 +3 794 819 807 +3 848 867 830 +3 822 867 848 +3 173 886 884 +3 188 844 189 +3 177 845 178 +3 173 884 174 +3 853 897 894 +3 853 894 837 +3 832 855 843 +3 885 887 123 +3 139 883 843 +3 865 888 180 +3 186 889 864 +3 124 885 123 +3 844 856 189 +3 849 885 125 +3 175 884 848 +3 843 883 832 +3 843 882 139 +3 188 881 844 +3 845 880 178 +3 848 894 822 +3 9 877 141 +3 165 877 9 +3 835 888 865 +3 864 889 836 +3 177 871 845 +3 848 878 175 +3 125 876 849 +3 820 904 855 +3 855 904 843 +3 830 878 848 +3 125 885 124 +3 79 853 80 +3 851 898 829 +3 174 884 175 +3 852 879 134 +3 884 886 837 +3 895 899 821 +3 140 883 139 +3 881 891 844 +3 845 890 880 +3 828 893 850 +3 167 854 166 +3 863 874 826 +3 833 874 863 +3 825 875 862 +3 862 875 834 +3 822 924 917 +3 841 904 863 +3 847 899 895 +3 189 856 190 +3 865 875 835 +3 836 874 864 +3 864 874 833 +3 834 875 865 +3 127 902 850 +3 134 903 852 +3 851 901 132 +3 860 915 842 +3 840 913 861 +3 838 887 885 +3 833 891 881 +3 880 890 834 +3 863 904 820 +3 873 891 820 +3 844 891 873 +3 132 898 851 +3 829 879 852 +3 130 858 129 +3 123 887 5 +3 5 887 78 +3 7 886 173 +3 137 859 136 +3 81 886 7 +3 850 925 828 +3 852 926 829 +3 829 918 851 +3 850 893 127 +3 180 888 181 +3 185 889 186 +3 824 915 860 +3 861 913 821 +3 917 924 849 +3 862 914 839 +3 829 898 879 +3 134 879 133 +3 842 922 860 +3 861 921 840 +3 179 865 180 +3 186 864 187 +3 823 914 862 +3 827 873 855 +3 866 895 821 +3 894 897 822 +3 176 871 177 +3 856 873 827 +3 854 912 827 +3 827 916 856 +3 829 870 866 +3 866 870 831 +3 828 869 867 +3 867 869 830 +3 857 916 827 +3 175 878 176 +3 837 907 853 +3 853 907 80 +3 853 908 838 +3 79 908 853 +3 126 876 125 +3 855 873 820 +3 832 919 855 +3 179 880 865 +3 864 881 187 +3 835 875 861 +3 826 874 860 +3 861 875 825 +3 860 874 836 +3 857 912 168 +3 182 868 183 +3 827 912 857 +3 890 892 823 +3 838 897 853 +3 844 873 856 +3 137 906 859 +3 863 920 841 +3 839 923 862 +3 865 880 834 +3 833 881 864 +3 860 922 826 +3 825 921 861 +3 176 878 871 +3 831 872 868 +3 868 872 183 +3 130 909 858 +3 858 911 129 +3 859 910 136 +3 191 916 857 +3 876 893 828 +3 128 902 127 +3 135 903 134 +3 132 901 131 +3 845 892 890 +3 168 912 167 +3 826 920 863 +3 862 923 825 +3 900 905 824 +3 183 872 184 +3 872 905 846 +3 139 882 138 +3 166 896 165 +3 167 912 854 +3 906 920 859 +3 832 896 854 +3 827 919 854 +3 861 899 835 +3 821 899 861 +3 836 900 860 +3 860 900 824 +3 182 927 868 +3 868 927 847 +3 854 896 166 +3 190 916 191 +3 854 919 832 +3 846 928 872 +3 831 905 872 +3 855 919 827 +3 862 890 823 +3 834 890 862 +3 820 891 863 +3 863 891 833 +3 909 921 858 +3 859 922 910 +3 858 923 911 +3 165 896 877 +3 828 917 876 +3 876 917 849 +3 871 878 830 +3 832 929 877 +3 822 917 867 +3 846 905 900 +3 187 881 188 +3 178 880 179 +3 883 929 832 +3 872 928 184 +3 168 930 857 +3 857 930 191 +3 856 916 190 +3 823 892 869 +3 127 893 126 +3 824 905 870 +3 888 899 847 +3 835 899 888 +3 889 900 836 +3 846 900 889 +3 78 908 79 +3 80 907 81 +3 830 892 871 +3 871 892 845 +3 866 918 829 +3 847 895 868 +3 868 895 831 +3 133 898 132 +3 831 895 866 +3 828 925 869 +3 829 926 870 +3 129 911 128 +3 136 910 135 +3 131 909 130 +3 821 918 866 +3 138 906 137 +3 869 892 830 +3 901 913 840 +3 851 913 901 +3 903 915 852 +3 842 915 903 +3 902 914 850 +3 839 914 902 +3 897 924 822 +3 882 906 138 +3 841 906 882 +3 843 904 882 +3 882 904 841 +3 841 920 906 +3 11 930 168 +3 191 930 11 +3 826 922 920 +3 920 922 859 +3 825 923 921 +3 921 923 858 +3 141 929 140 +3 184 928 185 +3 181 927 182 +3 867 917 828 +3 870 905 831 +3 126 893 876 +3 869 925 823 +3 870 926 824 +3 840 921 909 +3 910 922 842 +3 911 923 839 +3 877 896 832 +3 837 894 884 +3 884 894 848 +3 887 908 78 +3 81 907 886 +3 879 898 133 +3 877 929 141 +3 886 907 837 +3 838 908 887 +3 128 911 902 +3 135 910 903 +3 901 909 131 +3 913 918 821 +3 140 929 883 +3 840 909 901 +3 903 910 842 +3 902 911 839 +3 823 925 914 +3 824 926 915 +3 885 924 838 +3 849 924 885 +3 847 927 888 +3 888 927 181 +3 185 928 889 +3 889 928 846 +3 838 924 897 +3 851 918 913 +3 914 925 850 +3 915 926 852 +3 933 972 952 +3 933 973 951 +3 157 955 158 +3 186 957 185 +3 146 956 147 +3 952 1009 933 +3 951 1008 933 +3 960 980 941 +3 960 1023 980 +3 943 965 954 +3 142 997 996 +3 954 965 931 +3 959 1007 175 +3 142 996 143 +3 955 966 158 +3 931 1020 954 +3 144 996 958 +3 970 1016 151 +3 971 1015 181 +3 954 993 943 +3 948 1014 962 +3 962 1014 1012 +3 980 1023 934 +3 957 992 185 +3 956 991 147 +3 186 978 957 +3 173 1007 998 +3 157 981 955 +3 146 982 956 +3 11 990 191 +3 169 990 11 +3 175 1007 174 +3 931 985 955 +3 955 1002 931 +3 150 970 151 +3 182 971 181 +3 952 1016 970 +3 951 1015 971 +3 958 989 144 +3 993 1025 189 +3 174 1007 173 +3 970 1009 952 +3 971 1008 951 +3 175 988 959 +3 940 989 958 +3 958 1034 940 +3 143 996 144 +3 83 962 84 +3 190 993 189 +3 954 1020 963 +3 957 1006 992 +3 956 1005 991 +3 961 994 155 +3 177 1010 960 +3 935 1006 1004 +3 171 964 170 +3 941 1001 960 +3 960 1001 177 +3 975 986 944 +3 937 986 975 +3 936 987 974 +3 974 987 945 +3 158 966 159 +3 944 986 976 +3 976 986 947 +3 945 987 977 +3 977 987 946 +3 155 1013 961 +3 996 997 949 +3 992 1006 944 +3 991 1005 945 +3 954 1025 993 +3 939 994 961 +3 1004 1006 957 +3 173 998 7 +3 7 998 82 +3 180 968 179 +3 152 969 153 +3 6 997 142 +3 85 997 6 +3 961 1028 939 +3 974 1023 950 +3 975 1024 953 +3 934 1005 995 +3 963 1003 188 +3 973 1031 951 +3 972 1032 952 +3 187 978 186 +3 148 977 149 +3 184 976 183 +3 934 1023 974 +3 156 981 157 +3 145 982 146 +3 935 1024 975 +3 938 985 965 +3 995 1005 956 +3 966 985 938 +3 964 1022 938 +3 938 1026 966 +3 979 984 939 +3 942 984 979 +3 940 983 980 +3 980 983 941 +3 967 1026 938 +3 949 1018 962 +3 962 1018 84 +3 83 1019 962 +3 962 1019 948 +3 144 989 145 +3 965 985 931 +3 998 1007 948 +3 943 1029 965 +3 148 991 977 +3 184 992 976 +3 973 987 936 +3 946 987 973 +3 972 986 937 +3 947 986 972 +3 967 1022 172 +3 938 1022 967 +3 155 994 156 +3 962 1012 949 +3 955 985 966 +3 180 1015 968 +3 968 1017 179 +3 152 1016 969 +3 950 1033 974 +3 953 1030 975 +3 976 992 944 +3 977 991 945 +3 936 1031 973 +3 937 1032 972 +3 188 1003 187 +3 969 1021 153 +3 188 1025 963 +3 963 1020 942 +3 935 1004 979 +3 145 989 982 +3 160 1026 967 +3 154 1013 155 +3 172 1022 171 +3 942 1003 963 +3 178 1010 177 +3 975 1030 937 +3 974 1033 936 +3 176 988 175 +3 170 1011 169 +3 972 1008 947 +3 933 1008 972 +3 933 1009 973 +3 973 1009 946 +3 963 1025 954 +3 171 1022 964 +3 977 999 149 +3 947 1000 976 +3 976 1000 183 +3 946 999 977 +3 1014 1027 932 +3 1015 1031 968 +3 968 1033 1017 +3 1016 1032 969 +3 931 1002 984 +3 943 1011 964 +3 938 1029 964 +3 177 1001 176 +3 982 989 940 +3 1012 1014 932 +3 964 1011 170 +3 159 1026 160 +3 964 1029 943 +3 934 995 980 +3 156 994 981 +3 965 1029 938 +3 944 1006 975 +3 974 1005 934 +3 975 1006 935 +3 945 1005 974 +3 941 1027 988 +3 988 1027 959 +3 940 1034 983 +3 150 999 970 +3 971 1000 947 +3 970 999 946 +3 182 1000 971 +3 969 1030 1021 +3 169 1011 990 +3 943 1036 990 +3 981 994 939 +3 147 991 148 +3 185 992 184 +3 988 1001 941 +3 982 995 956 +3 940 995 982 +3 993 1036 943 +3 189 1025 188 +3 187 1003 978 +3 172 1037 967 +3 967 1037 160 +3 947 1008 971 +3 946 1009 970 +3 966 1026 159 +3 942 1004 978 +3 979 1004 942 +3 942 1020 984 +3 978 1003 942 +3 980 995 940 +3 932 1027 983 +3 939 1002 981 +3 981 1002 955 +3 959 1027 1014 +3 82 1019 83 +3 84 1018 85 +3 149 999 150 +3 183 1000 182 +3 939 1028 979 +3 1034 1035 932 +3 978 1004 957 +3 984 1002 939 +3 153 1021 154 +3 959 1014 1007 +3 1007 1014 948 +3 979 1028 935 +3 181 1015 180 +3 151 1016 152 +3 179 1017 178 +3 953 1024 1013 +3 1013 1024 961 +3 1010 1023 960 +3 950 1023 1010 +3 176 1001 988 +3 932 1035 1012 +3 1017 1033 950 +3 952 1032 1016 +3 951 1031 1015 +3 10 1037 172 +3 160 1037 10 +3 969 1032 1030 +3 1030 1032 937 +3 936 1033 1031 +3 1031 1033 968 +3 191 1036 190 +3 1021 1030 953 +3 984 1020 931 +3 990 1011 943 +3 998 1019 82 +3 85 1018 997 +3 983 1027 941 +3 983 1034 932 +3 958 1035 1034 +3 990 1036 191 +3 997 1018 949 +3 948 1019 998 +3 1010 1017 950 +3 178 1017 1010 +3 154 1021 1013 +3 935 1028 1024 +3 190 1036 993 +3 1013 1021 953 +3 949 1035 996 +3 996 1035 958 +3 1012 1035 949 +3 1024 1028 961 +4 42 43 290 402 +4 1038 220 239 273 +4 1039 486 419 454 +4 1040 204 293 268 +4 517 1041 1042 546 +4 1043 285 474 430 +4 1041 1044 1045 1046 +4 1047 1048 498 516 +4 1049 335 1050 1051 +4 1052 338 238 346 +4 1053 1054 1055 334 +4 1056 297 221 278 +4 1057 1053 1058 1059 +4 1060 444 520 557 +4 1061 1062 401 560 +4 1063 1064 1065 1066 +4 1067 219 272 266 +4 1043 430 474 476 +4 1068 281 283 217 +4 1069 1070 1071 1072 +4 1073 1074 1075 1076 +4 1043 258 226 240 +4 1077 569 520 556 +4 3 201 543 458 +4 198 242 13 14 +4 1078 1079 276 218 +4 1080 1081 1082 1083 +4 1084 1085 1086 1087 +4 1088 333 1089 358 +4 1090 1091 1092 362 +4 1058 365 1093 554 +4 1094 201 543 563 +4 536 73 367 558 +4 1095 1096 1097 1098 +4 1099 288 238 270 +4 1050 271 263 234 +4 1075 476 1074 470 +4 1040 293 232 268 +4 1100 1093 379 377 +4 1101 405 1061 383 +4 92 93 425 556 +4 203 372 351 16 +4 1102 1103 1104 407 +4 1105 292 233 267 +4 1063 1066 1065 1103 +4 1103 1039 1106 467 +4 1039 540 1107 503 +4 1058 365 71 337 +4 1108 446 258 450 +4 1102 1107 1104 1103 +4 1086 219 1081 266 +4 1109 1079 1110 1111 +4 1048 572 381 516 +4 1112 200 207 196 +4 1113 555 509 567 +4 1062 551 504 515 +4 1114 216 1094 194 +4 1115 1042 1116 527 +4 1117 1118 1075 1076 +4 26 197 514 25 +4 1045 565 566 514 +4 1061 558 536 367 +4 1095 1119 1097 1096 +4 1057 1120 1121 1095 +4 1122 1085 1087 1081 +4 1123 353 302 360 +4 1124 308 350 335 +4 1125 288 220 277 +4 1126 1127 1128 1115 +4 1104 1129 464 407 +4 1129 442 251 438 +4 1130 538 530 347 +4 1131 1132 1072 1133 +4 1134 199 1135 195 +4 47 435 244 482 +4 1040 1112 1136 212 +4 1041 507 1137 1138 +4 515 387 84 83 +4 1110 1079 1125 1091 +4 1138 352 373 202 +4 1128 550 1115 492 +4 1114 200 205 207 +4 1139 340 339 308 +4 1060 1102 441 557 +4 1061 528 1058 505 +4 1050 248 329 234 +4 259 364 35 234 +4 1140 385 398 388 +4 1141 1138 1137 315 +4 1095 1120 1075 1111 +4 1142 1143 1097 410 +4 1062 387 83 399 +4 1056 297 1136 298 +4 1141 1137 1044 1116 +4 1144 403 394 386 +4 1144 285 231 262 +4 1108 269 446 428 +4 1048 343 534 516 +4 1145 1082 416 440 +4 1080 1146 1085 1081 +4 1050 364 329 376 +4 1147 1125 220 277 +4 1148 355 311 326 +4 1093 377 328 379 +4 1145 260 256 447 +4 1083 272 219 250 +4 1146 235 1067 424 +4 52 424 254 438 +4 1149 336 361 301 +4 1115 1042 1149 1116 +4 1126 1150 1130 310 +4 1151 366 378 329 +4 19 202 352 2 +4 1152 1077 1060 444 +4 275 1153 1154 247 +4 1155 521 537 500 +4 1039 518 540 503 +4 1063 1064 1066 1103 +4 1077 456 425 444 +4 79 433 403 479 +4 1080 1156 1082 1081 +4 1062 395 387 384 +4 1053 317 334 379 +4 284 362 40 39 +4 1100 318 1113 377 +4 216 1114 1157 200 +4 1157 216 200 432 +4 1136 212 242 293 +4 1085 443 409 456 +4 201 458 23 484 +4 1158 199 1159 1134 +4 1060 570 497 523 +4 1158 199 18 323 +4 1138 193 211 202 +4 204 457 20 1 +4 1137 517 562 507 +4 242 212 13 293 +4 3 543 201 24 +4 59 452 5 262 +4 1160 500 522 548 +4 1067 266 272 235 +4 1058 71 365 554 +4 1144 1074 421 479 +4 1073 1074 420 470 +4 1042 322 539 513 +4 1039 549 1107 527 +4 201 543 563 24 +4 1131 1161 1113 1133 +4 1105 316 1159 375 +4 1092 362 1091 321 +4 523 1162 531 1060 +4 1083 1067 272 250 +4 1042 502 546 527 +4 366 32 252 300 +4 1140 280 286 243 +4 1163 1164 1120 1165 +4 1149 336 301 358 +4 1113 509 571 522 +4 1150 552 550 513 +4 1080 453 461 409 +4 1126 332 359 310 +4 1094 422 481 458 +4 1141 1046 1044 1137 +4 1166 298 1136 242 +4 1094 481 561 458 +4 1105 372 203 210 +4 198 1112 196 212 +4 1060 570 1102 557 +4 1086 266 1146 254 +4 1159 1135 1134 199 +4 1045 197 205 194 +4 1094 216 201 194 +4 1164 1144 1075 1165 +4 474 452 59 262 +4 1154 217 282 275 +4 1062 387 515 83 +4 1154 217 1127 282 +4 1148 375 1159 304 +4 1167 1155 521 460 +4 1041 1039 1116 527 +4 1143 414 446 450 +4 1148 326 1089 295 +4 1057 1120 1053 1059 +4 1057 547 1062 505 +4 1123 1059 1053 1120 +4 1090 1101 1092 1168 +4 1062 515 559 83 +4 394 452 78 479 +4 500 1160 521 548 +4 1094 458 201 484 +4 1094 561 506 543 +4 1041 545 1169 1039 +4 1041 517 566 546 +4 1090 1092 314 362 +4 1091 1099 257 227 +4 343 67 534 516 +4 1102 472 471 426 +4 1130 1170 1162 523 +4 1044 1094 1114 1157 +4 1171 304 1148 1141 +4 1158 323 1159 199 +4 1132 1051 1172 1083 +4 1144 474 285 262 +4 1159 1135 199 195 +4 1042 62 327 517 +4 1057 1163 1120 1059 +4 238 255 346 37 +4 1050 364 1172 234 +4 259 330 35 364 +4 1117 1062 1076 384 +4 1092 1090 314 368 +4 1173 1079 1110 1078 +4 393 74 4 345 +4 1131 380 318 331 +4 1153 222 253 247 +4 1049 335 303 320 +4 1126 1149 1127 1115 +4 1088 1089 300 236 +4 1166 198 214 242 +4 1099 342 338 307 +4 1128 1152 1104 1170 +4 1152 443 1085 456 +4 1058 337 71 528 +4 1090 393 385 404 +4 1073 553 1118 512 +4 1061 313 1059 337 +4 529 445 95 429 +4 1102 1103 407 472 +4 1109 1143 1142 1108 +4 1113 1133 1161 522 +4 1057 1120 1163 1062 +4 1147 1174 1125 1052 +4 1172 224 259 255 +4 393 400 74 345 +4 1109 1038 1142 1175 +4 1164 397 398 382 +4 1090 230 284 261 +4 1123 334 1053 317 +4 1057 1058 1176 508 +4 1045 211 514 564 +4 201 23 216 484 +4 1137 517 327 562 +4 492 1107 549 527 +4 1040 1136 297 293 +4 49 455 265 485 +4 1149 311 336 358 +4 282 1127 1089 1064 +4 1129 1146 412 438 +4 1113 555 567 519 +4 1072 1161 1131 1133 +4 299 1068 1129 251 +4 1081 219 1067 266 +4 15 267 203 294 +4 1141 1137 327 315 +4 1138 202 373 215 +4 1088 366 1151 252 +4 1107 472 454 419 +4 1144 394 452 262 +4 1101 389 405 383 +4 1130 1162 531 523 +4 1109 1098 1143 1043 +4 1084 464 1104 1129 +4 1100 377 305 331 +4 467 1177 1063 411 +4 1144 231 1140 290 +4 1088 366 333 319 +4 1063 436 467 411 +4 1144 474 1043 285 +4 1144 452 474 262 +4 1059 1058 337 356 +4 1178 1122 1156 1170 +4 1172 271 259 224 +4 1130 501 550 523 +4 1067 225 272 250 +4 1171 1089 1148 311 +4 1126 1150 359 301 +4 1049 1051 1050 1172 +4 1058 528 71 554 +4 1163 1101 1123 1059 +4 1176 1053 1070 1093 +4 1129 1103 473 407 +4 492 1107 527 1115 +4 536 392 6 85 +4 435 1063 1179 1177 +4 1099 238 338 270 +4 1040 1179 423 482 +4 1153 275 1154 1088 +4 1081 263 271 219 +4 1050 329 364 234 +4 1128 1130 550 523 +4 1083 272 1067 219 +4 516 571 1113 509 +4 1132 1147 1174 1175 +4 216 1114 1094 1157 +4 1166 298 294 233 +4 1093 365 328 70 +4 499 1180 525 1121 +4 1131 303 1049 350 +4 1050 263 1151 248 +4 1109 1071 1142 1143 +4 1131 1113 1100 318 +4 1090 261 284 41 +4 1123 1120 1092 1163 +4 1131 318 1100 331 +4 1113 572 1048 516 +4 1181 265 455 485 +4 1182 1135 1056 1136 +4 1048 325 343 516 +4 1048 534 498 516 +4 1183 273 1067 250 +4 1115 492 552 527 +4 542 564 27 202 +4 1166 298 242 294 +4 1138 211 564 202 +4 1045 1138 1046 211 +4 542 370 352 60 +4 1169 481 1094 434 +4 1157 422 1094 484 +4 1042 327 312 354 +4 1180 1119 499 532 +4 1061 505 536 558 +4 1100 379 1093 1055 +4 1113 1093 377 328 +4 241 257 342 39 +4 1183 1175 1132 1082 +4 1092 360 314 321 +4 1063 466 418 436 +4 485 1179 418 1181 +4 1150 1149 361 301 +4 343 325 67 516 +4 1183 1147 1038 273 +4 555 328 69 519 +4 569 1060 1047 1156 +4 1180 1161 1119 532 +4 1166 298 233 245 +4 1096 468 449 415 +4 479 394 452 1144 +4 1062 401 560 387 +4 1105 1159 1148 375 +4 1068 1181 265 299 +4 1150 552 1115 550 +4 1063 1103 436 473 +4 1182 1056 1135 1184 +4 1104 1127 1103 1115 +4 1139 1151 1126 306 +4 1090 1140 230 289 +4 1163 1101 1061 383 +4 1061 313 337 367 +4 1132 1174 1072 1175 +4 1052 357 309 330 +4 1117 395 384 390 +4 1060 441 444 557 +4 531 1060 526 497 +4 394 5 452 262 +4 80 79 433 390 +4 1150 1130 513 550 +4 1183 1142 1175 1082 +4 1066 1106 1103 1116 +4 1129 491 442 427 +4 1126 1149 1150 301 +4 1142 1097 1155 478 +4 531 523 1060 497 +4 317 1123 302 356 +4 1052 1172 357 330 +4 1164 1165 1075 1120 +4 1097 468 1096 415 +4 1052 309 338 346 +4 1163 1164 398 382 +4 243 388 43 44 +4 1042 539 322 349 +4 1137 562 327 370 +4 1089 264 300 236 +4 454 1039 486 540 +4 1132 1072 1133 1175 +4 1146 424 461 453 +4 1095 1075 1098 1111 +4 1179 291 232 244 +4 1091 1099 342 257 +4 389 368 324 75 +4 1142 1167 440 478 +4 1045 205 1094 194 +4 1169 1039 545 518 +4 455 299 1181 1068 +4 1068 1127 1064 1103 +4 1147 271 1172 224 +4 1176 525 508 568 +4 1130 530 1162 339 +4 1104 464 437 407 +4 1096 1098 1075 468 +4 1042 349 62 539 +4 1160 500 1155 522 +4 1129 473 464 407 +4 1077 462 448 425 +4 1099 227 288 270 +4 1172 259 271 234 +4 1099 257 227 270 +4 1045 1094 1169 506 +4 1130 530 339 347 +4 25 24 209 563 +4 228 1148 279 1056 +4 1086 1146 266 1067 +4 1153 1086 247 253 +4 1126 1150 1149 1115 +4 1062 504 1118 1076 +4 1099 338 342 270 +4 1178 1047 1124 1162 +4 1050 320 1172 364 +4 329 34 364 234 +4 393 4 45 261 +4 1053 1054 1110 1055 +4 1113 328 363 555 +4 1113 572 516 509 +4 514 209 25 197 +4 1044 1046 1114 205 +4 1064 246 229 278 +4 1062 1076 384 399 +4 90 490 89 524 +4 89 490 454 524 +4 1047 1048 1124 498 +4 1060 526 497 569 +4 1171 336 354 312 +4 1129 427 464 473 +4 1052 238 1099 288 +4 238 346 338 37 +4 1147 1052 1125 277 +4 1110 1054 1125 1055 +4 260 1145 256 225 +4 1041 1137 507 517 +4 47 244 435 48 +4 1158 1134 1046 206 +4 1063 1064 1103 1181 +4 1167 521 448 460 +4 1048 380 350 325 +4 1128 1060 1152 1170 +4 1077 556 448 521 +4 1145 1067 260 447 +4 1047 571 541 494 +4 1098 469 1043 476 +4 1155 445 529 429 +4 1097 1098 468 439 +4 1055 341 305 334 +4 1095 1097 1071 1098 +4 1101 389 76 405 +4 1078 1168 1092 1165 +4 1089 282 246 228 +4 77 405 369 76 +4 1180 525 496 532 +4 1089 326 348 295 +4 1088 282 1089 236 +4 1088 333 366 300 +4 366 329 248 33 +4 208 1112 198 1136 +4 1166 1136 198 242 +4 1110 1091 1078 1079 +4 1061 560 536 505 +4 394 5 78 452 +4 1076 553 475 535 +4 479 394 1144 403 +4 1080 462 1077 409 +4 264 333 300 31 +4 1160 522 1155 1161 +4 1169 518 506 561 +4 1045 1138 211 564 +4 1154 282 1088 275 +4 1144 1140 402 290 +4 1076 451 391 535 +4 1043 469 430 476 +4 1185 240 218 280 +4 1144 476 1043 474 +4 1075 408 1098 476 +4 1110 1125 1054 1091 +4 57 258 450 430 +4 1056 1179 1065 297 +4 1105 210 1159 372 +4 1129 251 254 438 +4 1182 1134 1184 1135 +4 1148 326 295 245 +4 1155 445 1119 529 +4 1043 240 285 430 +4 1158 1159 1141 1046 +4 348 333 264 31 +4 1105 233 292 245 +4 29 292 371 28 +4 1039 503 545 518 +4 1102 441 413 444 +4 1158 1159 323 374 +4 1068 491 1129 427 +4 1183 1145 1142 1082 +4 1050 263 248 234 +4 1147 1083 1172 271 +4 1147 250 271 224 +4 1099 342 257 270 +4 299 1068 251 237 +4 1152 413 443 456 +4 1057 547 505 528 +4 1056 1064 1065 1179 +4 1102 557 510 524 +4 1157 487 422 484 +4 389 1168 400 385 +4 1132 1131 1049 1051 +4 1183 1175 1147 1083 +4 1050 320 364 376 +4 1172 330 346 255 +4 1063 1179 1065 1064 +4 1088 319 358 301 +4 1166 298 1056 1136 +4 1134 1135 208 195 +4 203 351 267 0 +4 1158 193 199 206 +4 1158 373 323 18 +4 1149 1042 361 312 +4 1084 1086 1129 1087 +4 1126 359 332 301 +4 1129 442 412 464 +4 1167 462 1080 489 +4 238 338 270 37 +4 346 36 37 255 +4 346 36 255 330 +4 1079 1125 227 249 +4 1084 437 412 443 +4 1152 444 413 456 +4 1130 531 501 523 +4 1143 414 469 439 +4 1082 1160 1069 1133 +4 1167 489 1082 440 +4 1097 1098 1096 468 +4 1178 1124 1048 1051 +4 391 535 7 82 +4 351 28 267 0 +4 15 203 267 0 +4 3 23 201 458 +4 1076 406 391 451 +4 1062 83 559 399 +4 1061 401 1062 383 +4 1136 212 198 242 +4 1171 1149 1089 311 +4 1094 201 216 484 +4 216 22 200 432 +4 216 484 22 432 +4 1089 348 326 311 +4 216 484 23 22 +4 1105 351 203 372 +4 1134 1112 1114 207 +4 1134 208 199 195 +4 203 210 372 16 +4 1134 208 1112 207 +4 1065 297 1040 1136 +4 1135 198 208 195 +4 1182 1136 1134 1135 +4 1158 323 373 374 +4 1056 1064 1179 278 +4 1150 1042 513 322 +4 1113 572 363 381 +4 1185 1144 285 231 +4 1067 461 424 447 +4 239 55 269 428 +4 1078 1185 1168 1165 +4 256 447 54 459 +4 1143 463 410 428 +4 80 433 480 390 +4 1147 1067 1083 250 +4 1091 257 241 227 +4 1074 384 1076 390 +4 1164 398 1140 1168 +4 1073 420 1074 1076 +4 1080 1082 440 416 +4 531 1130 501 530 +4 1048 325 318 380 +4 1131 331 1049 303 +4 1182 1106 1066 1116 +4 1171 354 1042 312 +4 290 43 243 388 +4 42 5 394 262 +4 1102 510 557 570 +4 1137 370 327 315 +4 1068 427 455 491 +4 391 535 451 7 +4 391 7 451 81 +4 442 299 50 491 +4 1129 223 254 251 +4 1090 393 400 385 +4 1123 1110 1092 1165 +4 1142 1145 477 440 +4 1076 420 451 475 +4 1039 503 1107 549 +4 378 319 1088 1126 +4 1080 1085 453 409 +4 65 347 339 530 +4 1139 332 1126 310 +4 1096 533 97 512 +4 1109 226 1079 1043 +4 514 25 209 563 +4 201 563 209 24 +4 1171 1148 304 355 +4 515 387 560 84 +4 1117 1076 1062 1118 +4 337 1061 367 558 +4 1101 324 313 369 +4 1079 1043 226 274 +4 49 265 296 485 +4 49 485 296 48 +4 1166 1159 1135 1148 +4 1077 569 556 511 +4 448 556 425 93 +4 1171 354 1141 1042 +4 1102 471 1104 437 +4 1103 472 1107 419 +4 1171 336 1149 311 +4 1077 456 409 462 +4 1181 473 455 427 +4 1050 335 1122 1051 +4 1059 337 313 356 +4 55 256 54 459 +4 1045 1046 205 197 +4 1041 1042 546 527 +4 1070 1097 1095 1119 +4 239 55 428 459 +4 1080 453 1146 461 +4 1153 248 1151 263 +4 239 256 55 459 +4 542 27 2 202 +4 327 61 370 562 +4 64 347 538 322 +4 516 571 1048 1113 +4 1100 379 1055 305 +4 1139 1122 1126 1151 +4 1096 499 512 544 +4 1108 258 446 269 +4 1043 240 274 218 +4 65 339 66 530 +4 67 381 572 516 +4 1126 1153 1087 1088 +4 1128 492 1107 510 +4 1167 1080 1082 489 +4 1179 423 482 435 +4 1177 1112 1065 1040 +4 1158 18 199 215 +4 1063 1179 1064 1181 +4 1169 481 434 561 +4 1150 1130 1128 1170 +4 1158 1141 1159 374 +4 1157 484 1094 216 +4 1126 1088 1149 301 +4 52 254 424 235 +4 1137 1138 370 315 +4 1042 349 327 62 +4 1089 300 264 333 +4 1157 484 216 432 +4 1040 297 1179 232 +4 1173 1078 1110 1165 +4 1130 538 501 530 +4 64 538 513 322 +4 63 539 322 513 +4 1102 413 471 437 +4 454 1039 540 1107 +4 71 528 337 72 +4 1109 1055 1071 1111 +4 1173 1111 1110 1079 +4 1076 451 480 406 +4 1075 1165 1111 1120 +4 1080 1067 1081 1083 +4 1052 331 309 357 +4 1139 1130 339 310 +4 1084 1146 1085 453 +4 1103 419 1039 467 +4 52 254 51 438 +4 516 1047 1048 571 +4 1108 269 239 287 +4 1138 542 352 202 +4 1184 1066 1116 1182 +4 1171 1148 355 311 +4 1045 566 1138 564 +4 1141 1046 1137 1138 +4 1147 273 250 277 +4 540 454 89 486 +4 434 87 518 561 +4 90 557 490 524 +4 90 490 557 441 +4 90 557 91 441 +4 3 458 543 86 +4 543 86 458 561 +4 1095 1075 1096 1098 +4 1038 239 1145 256 +4 97 553 475 431 +4 475 553 99 535 +4 1121 499 1096 544 +4 1084 412 1146 453 +4 1069 1161 1155 1119 +4 1077 425 456 462 +4 79 78 479 403 +4 394 78 403 479 +4 1169 1039 518 434 +4 1102 471 472 407 +4 1088 282 1127 1089 +4 1153 275 1088 222 +4 1146 254 266 235 +4 1167 478 460 417 +4 565 1041 566 495 +4 1138 370 542 562 +4 373 215 19 18 +4 1151 252 366 248 +4 1056 246 1064 278 +4 279 1105 1166 1056 +4 1181 418 455 473 +4 1129 299 442 491 +4 390 1164 397 386 +4 1069 1133 1175 1082 +4 1061 337 1059 1058 +4 1169 1106 1044 1116 +4 242 214 294 14 +4 204 457 1 268 +4 1129 1181 427 473 +4 1104 1103 1129 407 +4 1041 495 1169 545 +4 1040 1136 293 212 +4 1158 199 193 215 +4 1103 407 472 436 +4 244 48 296 485 +4 455 49 299 491 +4 1160 1047 1156 511 +4 1121 1119 1180 1095 +4 1155 529 537 429 +4 97 512 553 431 +4 1134 192 205 206 +4 1039 1107 1115 527 +4 1169 1094 481 561 +4 1064 229 1179 278 +4 1068 1104 1103 1129 +4 1154 1127 1088 282 +4 1067 235 260 424 +4 1040 483 488 432 +4 1136 242 297 293 +4 442 251 50 299 +4 1169 1039 1106 1116 +4 1056 246 221 279 +4 1094 561 543 458 +4 1094 194 201 209 +4 1184 1066 1171 1116 +4 1041 565 1169 495 +4 1164 1075 1117 1120 +4 1098 1143 469 439 +4 1058 317 337 356 +4 1075 1144 1074 476 +4 442 51 50 251 +4 1068 1129 1181 427 +4 442 51 251 438 +4 1113 328 555 519 +4 1146 424 254 235 +4 1142 440 410 478 +4 1152 1085 1077 456 +4 1155 537 521 460 +4 1060 520 570 557 +4 1113 571 1133 522 +4 1136 208 1135 198 +4 1183 273 1038 225 +4 1056 1066 1064 246 +4 1128 523 550 492 +4 1040 232 1179 291 +4 1151 248 366 329 +4 1139 335 340 308 +4 1049 330 1172 320 +4 1115 552 1042 527 +4 391 81 451 406 +4 1092 1090 368 1101 +4 393 289 45 404 +4 393 45 289 261 +4 1163 398 1164 1168 +4 57 450 258 56 +4 49 491 50 299 +4 71 365 554 70 +4 378 1126 1151 306 +4 343 67 66 534 +4 531 1130 530 1162 +4 343 534 66 339 +4 21 213 483 20 +4 21 483 213 432 +4 21 200 22 432 +4 1129 251 442 299 +4 1172 1083 1081 271 +4 1080 440 1082 489 +4 63 539 62 349 +4 1180 496 522 532 +4 529 445 533 96 +4 1070 1093 1053 1055 +4 1057 1118 1062 551 +4 1079 218 1043 274 +4 368 324 314 1092 +4 348 295 30 31 +4 295 1148 228 1089 +4 348 326 30 295 +4 1052 341 1099 338 +4 363 68 555 69 +4 363 555 328 69 +4 47 482 291 46 +4 327 62 61 517 +4 1041 1045 1138 1046 +4 542 60 352 2 +4 542 562 370 60 +4 1103 1116 1106 1039 +4 208 1112 207 198 +4 1177 1040 1065 1179 +4 291 268 46 457 +4 291 46 482 457 +4 47 244 291 482 +4 1113 1093 328 519 +4 1139 1126 1122 1170 +4 1067 424 260 447 +4 286 1090 1078 1168 +4 65 64 347 538 +4 65 347 530 538 +4 565 1041 1045 566 +4 1178 1133 1047 1156 +4 1042 322 312 349 +4 1081 219 1083 1067 +4 1042 62 517 539 +4 1045 1094 563 209 +4 42 402 290 262 +4 42 394 402 262 +4 1144 1074 403 386 +4 1145 416 477 440 +4 1052 338 1099 238 +4 1049 1050 335 320 +4 1167 521 1077 448 +4 1107 492 549 510 +4 1150 361 359 301 +4 1094 543 201 458 +4 1039 545 503 527 +4 1094 543 506 563 +4 66 339 534 530 +4 92 91 520 444 +4 92 444 520 425 +4 1052 1172 346 255 +4 366 33 252 32 +4 446 269 258 56 +4 446 258 450 56 +4 446 55 269 56 +4 446 428 269 55 +4 1105 1148 326 355 +4 1105 233 1166 267 +4 284 362 41 40 +4 1090 41 362 345 +4 1090 1091 1078 1092 +4 15 294 214 14 +4 15 294 203 214 +4 1063 435 1179 418 +4 1040 457 483 204 +4 1040 457 204 268 +4 1166 1159 1148 1105 +4 1040 293 204 212 +4 1113 1048 572 381 +4 1067 272 260 235 +4 279 1166 245 298 +4 1045 506 1169 565 +4 26 211 27 564 +4 26 514 211 564 +4 1057 1120 1062 1118 +4 1058 554 508 528 +4 337 72 528 558 +4 337 367 72 558 +4 1080 462 409 489 +4 1174 1099 1052 341 +4 1150 359 361 322 +4 366 32 300 333 +4 1088 300 1089 333 +4 1088 358 1149 301 +4 1126 359 1150 310 +4 1127 1149 1089 1066 +4 1130 339 310 347 +4 1056 228 246 279 +4 1149 361 336 312 +4 1042 517 502 539 +4 289 243 44 404 +4 289 44 45 404 +4 1167 511 1077 521 +4 1079 1099 1125 1091 +4 1101 1061 405 369 +4 395 1164 1117 1163 +4 1101 369 405 76 +4 39 1091 362 321 +4 57 285 240 430 +4 474 57 430 285 +4 1043 1108 258 450 +4 1043 450 258 430 +4 1043 240 57 258 +4 1097 410 465 478 +4 199 323 210 17 +4 199 18 323 17 +4 1158 1046 193 206 +4 1090 385 1168 404 +4 481 86 87 561 +4 481 87 434 561 +4 1159 199 210 195 +4 481 86 561 458 +4 1041 1039 1169 1116 +4 1094 422 458 484 +4 1159 210 199 323 +4 1156 1082 1081 1083 +4 1049 357 1172 330 +4 1126 1130 1150 1170 +4 53 260 447 54 +4 1109 1108 1038 287 +4 1155 1161 522 532 +4 1072 1161 1100 1131 +4 1109 1143 1108 1043 +4 1185 231 285 240 +4 537 95 94 460 +4 537 94 521 460 +4 1142 1175 1072 1071 +4 1155 537 529 500 +4 537 95 460 429 +4 260 54 256 447 +4 53 260 424 447 +4 1085 1087 1104 1170 +4 53 235 52 424 +4 348 264 295 31 +4 257 38 342 39 +4 257 342 38 270 +4 1173 1075 1144 1165 +4 1132 1175 1133 1082 +4 220 1109 249 1125 +4 363 572 555 68 +4 1104 1126 1170 1087 +4 1084 453 1085 409 +4 1164 1074 1144 386 +4 1173 1109 1098 1071 +4 1091 342 241 257 +4 540 89 88 486 +4 1065 1040 297 1179 +4 540 88 518 486 +4 540 89 454 524 +4 1063 435 418 466 +4 198 13 242 212 +4 198 214 242 14 +4 1077 425 448 556 +4 1131 350 1048 380 +4 1144 231 290 262 +4 30 295 326 245 +4 1158 374 373 315 +4 1138 373 352 315 +4 1134 1136 1112 208 +4 80 81 406 480 +4 80 406 390 480 +4 1134 207 1114 192 +4 1041 495 545 527 +4 1169 506 1094 561 +4 1157 1039 434 467 +4 1138 564 566 507 +4 1105 1166 203 267 +4 1042 546 502 517 +4 29 326 371 245 +4 1040 1112 212 196 +4 279 1148 1105 1056 +4 1153 1081 1122 1087 +4 1157 434 1094 422 +4 1081 271 1083 219 +4 1107 454 472 426 +4 1042 513 502 552 +4 1130 538 347 322 +4 1103 1115 1039 1107 +4 1171 355 304 336 +4 1084 412 453 443 +4 1166 198 1136 1135 +4 1098 469 476 408 +4 1173 1109 1111 1079 +4 1123 360 302 356 +4 1101 313 1061 369 +4 1043 258 1108 226 +4 370 60 562 61 +4 1138 352 370 315 +4 542 2 352 202 +4 1040 204 213 196 +4 467 1177 1106 1063 +4 1166 198 1135 195 +4 373 352 19 202 +4 1041 545 1039 527 +4 327 1141 1042 1137 +4 1140 243 230 289 +4 1090 1101 400 368 +4 1090 362 314 345 +4 1160 1077 1156 1167 +4 1109 1098 1071 1143 +4 1097 439 465 463 +4 1090 289 393 404 +4 97 96 533 449 +4 1097 1143 1098 439 +4 1105 1159 316 372 +4 1166 195 1135 1159 +4 1164 397 1140 398 +4 1074 433 421 479 +4 1117 395 1062 384 +4 1123 1092 1120 1165 +4 1079 249 274 226 +4 1096 512 97 431 +4 1096 97 449 431 +4 1074 476 433 470 +4 1128 523 492 510 +4 1139 339 340 310 +4 1040 423 488 483 +4 455 49 265 299 +4 1103 1107 1039 419 +4 1134 1135 1136 208 +4 1067 273 225 250 +4 1090 1078 1091 286 +4 1050 1083 1172 1051 +4 1101 324 369 76 +4 1117 1076 1074 384 +4 1117 1120 1075 1118 +4 1074 476 421 433 +4 1076 451 535 475 +4 1179 244 229 296 +4 1041 507 566 517 +4 559 535 399 82 +4 559 399 83 82 +4 1074 480 1076 420 +4 1062 384 387 399 +4 88 434 518 486 +4 88 518 434 87 +4 1077 520 1060 444 +4 570 1128 1102 510 +4 1052 309 341 338 +4 285 474 59 262 +4 1043 430 469 450 +4 1144 402 394 262 +4 285 59 474 58 +4 1124 350 1051 335 +4 1077 520 425 556 +4 254 251 51 438 +4 1146 266 1067 235 +4 1040 488 1112 432 +4 485 1179 435 418 +4 1040 204 483 213 +4 536 392 85 401 +4 536 85 560 401 +4 1108 428 239 269 +4 53 260 235 424 +4 260 1145 225 1067 +4 1048 381 318 325 +4 1080 409 461 489 +4 1047 571 1133 1048 +4 1094 434 481 422 +4 1138 507 542 564 +4 1166 210 203 195 +4 26 514 197 211 +4 1090 261 393 289 +4 1164 1074 1075 1144 +4 1043 430 57 240 +4 74 400 368 345 +4 1090 1092 1078 1168 +4 1039 503 549 527 +4 1179 291 244 482 +4 1138 562 542 507 +4 1042 327 349 312 +4 1140 1090 230 286 +4 284 241 362 39 +4 1163 387 395 396 +4 1171 1148 1066 1184 +4 1102 510 1107 524 +4 1183 1175 1038 1147 +4 1067 225 260 272 +4 1160 1167 1156 1082 +4 1063 467 1103 1106 +4 1130 513 501 538 +4 1103 419 467 436 +4 1039 419 1107 454 +4 1166 195 1159 210 +4 1096 533 512 499 +4 338 270 38 342 +4 1052 346 238 255 +4 338 38 270 37 +4 1100 1093 1161 1055 +4 1074 433 420 470 +4 451 535 475 99 +4 1075 468 1098 408 +4 451 480 406 81 +4 1057 1053 1176 1058 +4 1090 400 1168 385 +4 389 324 76 75 +4 1117 1075 1074 1076 +4 389 400 368 75 +4 1076 559 504 535 +4 1069 1097 1070 1119 +4 1076 504 553 535 +4 1075 408 476 470 +4 1062 515 504 559 +4 1173 1111 1109 1071 +4 367 73 72 558 +4 1090 1168 1140 404 +4 1078 276 1091 241 +4 1052 1172 330 346 +4 1109 1110 1125 1055 +4 1052 341 309 331 +4 478 1097 1155 429 +4 1172 259 330 255 +4 254 1086 1129 1146 +4 1057 1061 1058 505 +4 211 202 27 564 +4 1182 1157 1044 1114 +4 1158 1134 1159 1046 +4 1138 215 193 202 +4 1041 1138 1137 1046 +4 1158 1138 1141 315 +4 1137 562 1138 507 +4 1041 507 1138 566 +4 560 84 401 85 +4 536 367 73 344 +4 560 84 387 401 +4 1101 1059 313 356 +4 1073 475 553 431 +4 1070 1161 1093 1055 +4 522 1180 567 496 +4 1144 476 474 421 +4 1101 324 360 356 +4 1043 469 414 450 +4 1058 554 1093 508 +4 1174 1100 341 1052 +4 395 1164 390 1117 +4 1109 1142 1038 1108 +4 1140 230 243 286 +4 1173 1144 1098 1043 +4 1144 421 474 452 +4 445 449 533 96 +4 1097 463 465 410 +4 1160 1156 1133 1082 +4 1142 1155 1167 478 +4 1085 409 1077 456 +4 1139 335 1122 306 +4 1048 381 325 516 +4 1067 461 447 416 +4 1050 329 1151 376 +4 1121 1119 1096 499 +4 1058 365 337 317 +4 1129 412 442 438 +4 1096 97 533 449 +4 529 95 537 429 +4 1038 220 1147 1175 +4 1080 1085 409 1077 +4 1147 220 273 277 +4 259 330 255 36 +4 259 35 330 36 +4 77 405 392 344 +4 6 344 77 392 +4 1061 369 313 344 +4 1100 318 377 331 +4 1101 396 389 383 +4 1168 1140 1078 286 +4 1091 284 241 362 +4 1091 241 276 227 +4 1141 1159 1184 1046 +4 1104 1068 1127 1154 +4 1171 1066 1148 1089 +4 1045 514 563 565 +4 1043 226 274 240 +4 1061 505 1062 560 +4 1079 1091 276 227 +4 1139 339 1124 308 +4 1086 266 254 223 +4 1132 1174 1100 1072 +4 1173 1185 1144 1043 +4 1080 453 1085 1146 +4 1045 563 506 565 +4 1171 355 336 311 +4 1105 203 1166 210 +4 1063 1103 467 436 +4 1056 298 279 221 +4 1112 196 213 200 +4 1166 195 203 214 +4 1166 214 198 195 +4 1093 568 508 554 +4 1100 305 1055 341 +4 1100 305 341 331 +4 1069 1175 1142 1082 +4 4 345 41 261 +4 1043 57 430 258 +4 1038 1145 225 256 +4 1052 330 309 346 +4 286 1090 284 1091 +4 1095 1098 1071 1111 +4 1052 238 288 277 +4 536 344 6 392 +4 1163 1101 1092 1123 +4 77 369 405 344 +4 35 364 34 234 +4 1050 1172 1083 1081 +4 1068 281 251 237 +4 30 326 29 245 +4 1148 228 279 245 +4 29 371 292 245 +4 1069 1119 1070 1161 +4 448 94 521 93 +4 448 460 521 94 +4 1058 1093 365 317 +4 1078 1140 1185 286 +4 1038 287 239 220 +4 248 34 329 234 +4 248 33 329 34 +4 1076 391 399 535 +4 1163 387 1062 395 +4 1076 559 535 399 +4 203 16 351 0 +4 520 444 91 557 +4 92 425 520 556 +4 448 521 556 93 +4 1077 425 520 444 +4 1114 216 194 200 +4 1056 297 1065 1136 +4 1136 297 242 298 +4 1105 375 1148 355 +4 279 1105 245 1166 +4 1084 464 1129 412 +4 1090 1101 1168 400 +4 321 1054 1123 353 +4 1108 226 258 269 +4 1131 1132 1100 1072 +4 1097 445 1155 429 +4 67 381 68 572 +4 67 325 381 516 +4 46 1 457 268 +4 1138 352 542 370 +4 373 202 19 215 +4 1166 233 294 267 +4 1041 1138 1045 566 +4 282 1127 1064 217 +4 299 1181 265 455 +4 536 6 344 73 +4 1062 401 387 383 +4 1167 440 478 417 +4 1098 439 469 408 +4 300 333 32 31 +4 1088 378 1151 366 +4 366 248 252 33 +4 79 433 390 403 +4 1163 1168 1164 1165 +4 1144 403 1074 479 +4 1132 1052 1174 1147 +4 1068 1154 281 217 +4 1113 1161 1093 567 +4 1113 555 363 572 +4 1139 1124 335 308 +4 500 1160 1155 521 +4 1162 531 526 498 +4 1126 1104 1127 1087 +4 1144 479 421 452 +4 1144 290 402 262 +4 1144 386 394 402 +4 1073 475 1076 553 +4 529 95 445 96 +4 1095 1121 1096 1073 +4 528 1061 1058 337 +4 1057 1121 1120 1118 +4 1061 536 560 401 +4 97 98 475 553 +4 1076 480 451 420 +4 475 98 99 553 +4 1137 1138 562 370 +4 1076 384 406 390 +4 451 99 7 535 +4 1142 477 410 440 +4 1076 399 391 384 +4 1099 307 338 341 +4 1050 1172 271 234 +4 1146 438 254 424 +4 74 368 400 75 +4 1077 569 1060 520 +4 1129 254 1146 438 +4 39 1091 241 362 +4 1127 1149 1066 1103 +4 69 519 328 70 +4 21 213 200 432 +4 483 20 204 457 +4 483 213 204 20 +4 528 1061 337 558 +4 321 1092 1123 1091 +4 1076 391 406 384 +4 393 345 4 261 +4 1163 1168 1092 1101 +4 1077 556 521 511 +4 1109 220 1038 1125 +4 1039 1115 1116 527 +4 1040 291 1179 482 +4 1088 275 252 222 +4 1065 1136 1040 1112 +4 1050 1051 1122 1081 +4 1158 199 1134 206 +4 1064 1181 1179 229 +4 1166 294 203 267 +4 1089 333 311 358 +4 1091 241 284 286 +4 1061 528 505 558 +4 1057 508 1176 493 +4 1123 1101 1092 360 +4 1057 1062 547 551 +4 1140 386 402 388 +4 1128 1107 1102 510 +4 1150 1042 1115 552 +4 1166 214 203 294 +4 244 435 48 485 +4 1054 302 353 334 +4 1156 1060 1162 1170 +4 1109 226 1043 1108 +4 63 64 513 322 +4 327 61 562 517 +4 63 322 539 349 +4 1138 564 542 202 +4 499 1180 1121 1119 +4 1083 250 219 271 +4 1080 440 489 416 +4 1166 1136 1056 1135 +4 1102 1107 472 426 +4 1177 423 1040 1179 +4 1171 1042 1149 312 +4 1050 271 1172 1081 +4 1046 206 205 197 +4 1046 193 206 197 +4 290 43 388 402 +4 1100 1093 1113 1161 +4 1040 212 204 196 +4 204 12 293 268 +4 204 293 12 212 +4 204 1 12 268 +4 210 372 16 17 +4 210 323 372 17 +4 1042 539 502 513 +4 228 1148 1056 1089 +4 1182 1044 1157 1106 +4 1056 1179 297 278 +4 1040 297 232 293 +4 1112 207 198 196 +4 1057 1062 1061 505 +4 1117 384 1074 390 +4 243 388 44 404 +4 1140 1090 286 1168 +4 1123 1053 1058 317 +4 12 13 212 293 +4 391 399 535 82 +4 379 1055 1053 1093 +4 1102 1104 471 407 +4 444 441 91 557 +4 1156 1080 1167 1077 +4 531 1060 1162 526 +4 1153 1088 1151 222 +4 1174 1099 1054 1125 +4 363 572 68 381 +4 1142 410 1097 478 +4 1093 328 519 70 +4 1093 554 365 70 +4 1093 519 554 70 +4 1123 1120 1163 1059 +4 1047 494 526 511 +4 1113 509 522 567 +4 1078 276 286 218 +4 1113 377 363 328 +4 1131 1161 1100 1113 +4 321 1054 1091 1123 +4 279 1148 245 1105 +4 1101 368 389 400 +4 1128 1152 1102 1104 +4 1094 209 201 563 +4 1039 540 518 486 +4 1126 319 1088 301 +4 1139 1170 1178 1162 +4 310 1150 322 359 +4 1105 203 351 267 +4 292 267 371 28 +4 371 267 351 28 +4 1068 1129 491 299 +4 1107 454 426 490 +4 1088 275 282 236 +4 474 57 285 58 +4 1045 563 1094 506 +4 1046 211 1138 193 +4 1046 197 211 193 +4 1158 1046 1141 1138 +4 1042 327 1137 517 +4 1115 492 550 552 +4 1041 1116 1042 527 +4 1042 552 502 527 +4 1179 229 1181 296 +4 1042 361 312 322 +4 1130 513 550 501 +4 1056 1066 1065 1064 +4 1107 454 490 524 +4 1107 540 454 524 +4 1107 503 540 524 +4 1107 510 549 524 +4 1107 549 503 524 +4 1166 1056 1148 1135 +4 1157 434 422 487 +4 1171 1149 336 312 +4 1169 434 518 561 +4 1039 434 467 419 +4 1039 518 434 486 +4 1039 486 434 419 +4 1068 1103 1104 1127 +4 1103 472 419 436 +4 1114 1094 205 194 +4 1177 1065 1182 1106 +4 1177 1157 432 488 +4 1103 1116 1039 1115 +4 1050 1081 1153 263 +4 1103 473 407 436 +4 1156 1082 1167 1080 +4 1129 281 223 251 +4 1056 246 1089 1066 +4 1103 1116 1115 1149 +4 1181 455 418 485 +4 1181 229 265 296 +4 1181 296 265 485 +4 1181 283 265 229 +4 1063 1179 1177 1065 +4 1177 1157 487 411 +4 1177 432 1157 1112 +4 1179 1181 485 296 +4 1179 485 244 296 +4 1064 246 282 217 +4 1179 229 244 278 +4 1086 266 1081 1067 +4 1179 278 244 297 +4 1179 244 232 297 +4 1179 482 244 435 +4 1063 1065 1177 1106 +4 1179 435 244 485 +4 1066 1116 1103 1149 +4 1056 1089 246 228 +4 1084 1085 443 409 +4 1182 1157 1114 1112 +4 327 1141 354 1042 +4 1141 1044 1046 1184 +4 1088 300 252 236 +4 1064 246 1089 282 +4 1166 242 214 294 +4 1148 311 1089 326 +4 1089 282 264 236 +4 1089 295 348 264 +4 1089 295 264 228 +4 1089 264 348 333 +4 1089 333 348 311 +4 1089 311 1149 358 +4 1089 264 282 228 +4 1114 207 205 192 +4 198 1112 212 1136 +4 1105 326 375 355 +4 432 1040 213 1112 +4 1177 435 488 423 +4 1134 192 208 207 +4 1040 213 1112 196 +4 1182 1136 1056 1065 +4 432 1040 483 213 +4 1177 432 1112 488 +4 1177 487 1157 488 +4 1177 487 488 411 +4 1112 200 213 432 +4 1056 221 246 278 +4 1177 1112 1040 488 +4 1040 268 232 291 +4 1040 268 291 457 +4 1040 291 482 457 +4 1040 482 423 457 +4 1040 457 423 483 +4 1146 424 453 438 +4 1150 550 1128 1130 +4 1084 1104 464 437 +4 1146 453 412 438 +4 1129 442 464 427 +4 1129 1103 1181 473 +4 1068 265 283 237 +4 1152 456 1077 444 +4 1127 1149 1103 1115 +4 1151 329 378 376 +4 1131 380 1048 318 +4 1068 265 237 299 +4 1060 441 1102 444 +4 1132 1049 1052 1172 +4 1068 265 1181 283 +4 1084 1104 1085 1087 +4 1153 1126 1087 1122 +4 1156 569 1077 511 +4 1047 541 526 494 +4 1178 1048 1047 1133 +4 516 1047 571 541 +4 1068 427 1181 455 +4 1154 1129 281 223 +4 1084 1085 1152 443 +4 1068 281 1129 251 +4 1084 464 412 437 +4 1126 1150 1128 1170 +4 1178 1156 1047 1162 +4 1128 1102 1152 1060 +4 523 1162 1060 1170 +4 1150 1042 552 513 +4 1153 248 263 222 +4 1104 471 407 437 +4 1104 1115 1103 1107 +4 1102 1107 1103 472 +4 1154 1087 1104 1129 +4 1128 1060 523 570 +4 1139 340 332 310 +4 1150 1128 550 1115 +4 1102 471 413 441 +4 1102 426 471 441 +4 1102 1107 490 524 +4 1102 490 557 524 +4 1102 490 1107 426 +4 1102 490 426 441 +4 1102 557 490 441 +4 444 1152 1102 1060 +4 1084 1152 437 443 +4 1060 520 569 570 +4 1060 569 497 570 +4 1160 521 1167 1155 +4 1124 1051 1122 335 +4 1160 1156 1077 511 +4 1100 379 305 377 +4 1156 1122 1081 1085 +4 1130 513 538 322 +4 1156 1060 1077 569 +4 1155 529 1119 532 +4 1167 417 489 440 +4 1155 537 460 429 +4 1155 522 500 532 +4 1139 306 1126 332 +4 1086 1154 247 223 +4 1086 253 219 266 +4 1160 1077 1167 511 +4 1131 1051 1124 350 +4 1167 448 417 460 +4 1122 1087 1085 1170 +4 1130 347 310 322 +4 1047 511 526 569 +4 1069 1082 1142 1167 +4 1162 531 498 530 +4 1162 534 339 530 +4 1162 498 534 530 +4 1162 534 343 339 +4 1139 1126 1130 310 +4 1049 1051 350 335 +4 1124 1048 534 498 +4 1050 1083 1051 1081 +4 1050 271 1081 263 +4 317 1123 356 1058 +4 1052 255 238 277 +4 1183 1175 1142 1038 +4 1131 350 1124 1048 +4 378 1126 306 332 +4 1139 340 335 306 +4 1050 1153 1081 1122 +4 1151 378 306 376 +4 1050 248 1151 329 +4 1156 1051 1082 1083 +4 1139 1122 1151 306 +4 1088 333 358 319 +4 1088 378 366 319 +4 1126 1104 1128 1127 +4 1088 236 252 275 +4 1128 1115 1107 492 +4 1126 1151 1088 378 +4 378 319 1126 332 +4 1153 247 1086 1154 +4 1086 247 253 223 +4 1153 1151 1126 1122 +4 1088 300 366 252 +4 1088 252 1151 222 +4 1151 252 248 222 +4 1153 1154 1086 1087 +4 1104 1126 1128 1170 +4 1088 358 1089 1149 +4 1088 1089 1127 1149 +4 1172 364 259 234 +4 1172 330 259 364 +4 1172 330 364 320 +4 1143 446 1108 450 +4 1049 1172 1050 320 +4 1131 303 350 380 +4 1108 428 1145 239 +4 1092 314 362 321 +4 1180 1119 1070 1095 +4 1142 1108 1143 1145 +4 1038 225 239 256 +4 1109 1038 220 287 +4 1142 1038 1108 1145 +4 1119 533 445 449 +4 1163 398 1168 396 +4 1038 287 1108 239 +4 1038 1125 220 1175 +4 1038 273 239 225 +4 1143 1145 428 477 +4 1145 459 239 428 +4 1145 256 239 459 +4 1145 447 256 459 +4 1124 534 1162 498 +4 1145 416 1067 447 +4 1145 416 447 459 +4 1145 477 459 428 +4 1145 477 416 459 +4 287 1109 226 249 +4 1108 226 269 287 +4 1097 1143 439 463 +4 1132 1052 1147 1172 +4 1174 1054 1099 341 +4 1091 241 342 39 +4 1091 342 321 39 +4 1055 305 379 334 +4 1093 568 554 519 +4 1093 496 568 567 +4 1093 567 568 519 +4 379 1055 334 1053 +4 551 1057 493 547 +4 1053 317 379 1093 +4 1093 365 317 379 +4 1093 328 365 379 +4 1057 1095 1176 1053 +4 1057 1120 1095 1053 +4 1101 313 324 356 +4 1180 522 1161 532 +4 1090 289 230 261 +4 1053 1111 1110 1120 +4 1078 241 1091 286 +4 1123 1059 1101 356 +4 395 1164 1163 382 +4 1110 1120 1111 1165 +4 1073 420 475 431 +4 1096 1119 533 499 +4 1062 505 515 560 +4 1062 559 1076 399 +4 1070 1095 1097 1071 +4 1101 76 389 324 +4 1082 1132 1051 1133 +4 1109 1110 1055 1111 +4 1123 1120 1110 1165 +4 1113 509 555 572 +4 1176 1093 1180 568 +4 1097 468 415 439 +4 1155 460 478 429 +4 1109 1142 1071 1175 +4 1113 567 1093 519 +4 1079 1099 1091 227 +4 1109 1125 1110 1079 +4 1097 1071 1098 1143 +4 1070 1111 1071 1055 +4 1142 1145 1143 477 +4 1173 1110 1111 1165 +4 1097 465 445 429 +4 1160 511 521 548 +4 1113 1048 1133 571 +4 1047 511 569 1156 +4 1131 380 331 303 +4 1100 1113 1093 377 +4 1047 526 1162 1060 +4 1155 500 529 532 +4 1075 1098 1144 476 +4 1142 1071 1097 1143 +4 1069 1070 1072 1161 +4 1125 1052 288 277 +4 551 1057 1121 493 +4 1079 1125 1099 227 +4 1156 1081 1051 1083 +4 478 1097 429 465 +4 1142 1143 410 477 +4 1057 528 1058 508 +4 1176 1180 525 568 +4 499 1121 525 544 +4 1119 533 529 445 +4 1119 529 533 499 +4 1119 529 499 532 +4 1167 478 1155 460 +4 1155 1119 1161 532 +4 1097 1143 463 410 +4 1113 522 1161 567 +4 1160 1133 522 1161 +4 1160 511 1167 521 +4 1131 1100 1052 331 +4 1113 318 1048 381 +4 1113 363 318 381 +4 1113 318 363 377 +4 1074 403 433 479 +4 1062 551 1118 504 +4 1074 480 420 433 +4 1074 406 1076 480 +4 1074 1076 406 390 +4 1074 406 480 390 +4 1163 1061 1062 383 +4 1185 1165 1140 1168 +4 390 1164 386 1074 +4 1074 390 433 403 +4 1074 390 403 386 +4 1074 480 433 390 +4 1163 396 395 382 +4 1062 504 1076 559 +4 1073 1121 1096 512 +4 1118 553 504 512 +4 1096 1119 449 533 +4 1121 493 1176 525 +4 1121 512 1118 551 +4 1118 512 504 551 +4 1057 1176 1121 493 +4 1062 515 547 551 +4 1062 547 515 505 +4 1163 1168 1101 396 +4 1062 560 515 387 +4 1057 508 493 547 +4 1061 313 367 344 +4 1061 405 369 344 +4 1061 405 392 383 +4 1061 392 536 401 +4 1061 392 401 383 +4 1061 367 536 344 +4 1061 344 392 405 +4 1061 344 536 392 +4 396 1168 389 398 +4 1101 1059 1061 313 +4 1173 1098 1111 1071 +4 368 324 1092 1101 +4 1101 324 389 368 +4 1140 385 1168 398 +4 1173 1075 1165 1111 +4 1090 261 41 345 +4 1092 1101 324 360 +4 1090 1140 289 404 +4 1090 368 400 345 +4 1057 551 1121 1118 +4 396 1168 1101 389 +4 1168 389 398 385 +4 1185 240 1043 218 +4 389 1168 1101 400 +4 1140 402 290 388 +4 1140 398 397 388 +4 1092 324 314 360 +4 1121 1176 1180 525 +4 1123 321 353 360 +4 1069 1097 1142 1071 +4 1163 382 398 396 +4 1163 1092 1165 1120 +4 1090 284 1091 362 +4 1123 302 334 317 +4 1163 1165 1092 1168 +4 1090 41 284 362 +4 321 1092 360 1123 +4 1140 397 386 388 +4 1140 1168 385 404 +4 1140 385 388 404 +4 286 1090 230 284 +4 1140 243 289 404 +4 1140 243 231 280 +4 1140 290 231 243 +4 1140 290 243 388 +4 1164 1117 1074 390 +4 1140 388 243 404 +4 1163 1061 1101 1059 +4 1144 402 1140 386 +4 1185 1043 1079 218 +4 1144 421 1074 476 +4 1185 231 240 280 +4 1185 285 1144 1043 +4 1063 1065 1106 1103 +4 1157 1112 432 200 +4 1177 1182 1065 1112 +4 1157 432 488 487 +4 1157 487 484 432 +4 1157 467 1106 1039 +4 1177 1179 435 423 +4 1157 411 467 487 +4 1157 467 434 487 +4 1114 1112 1157 200 +4 1114 205 200 194 +4 1114 1112 200 207 +4 1134 206 208 192 +4 1134 205 1046 206 +4 1134 206 199 208 +4 1169 545 565 518 +4 1045 197 514 211 +4 1045 1046 197 211 +4 1066 1182 1184 1056 +4 1045 1046 1044 205 +4 1141 327 374 315 +4 1158 1141 374 315 +4 1169 565 545 495 +4 1041 1169 1045 1044 +4 1045 205 1114 1094 +4 1182 1112 1134 1136 +4 1169 1157 1044 1106 +4 1169 1039 1157 1106 +4 1169 434 1157 1039 +4 1169 1157 434 1094 +4 1169 506 518 565 +4 1169 1094 1044 1157 +4 1045 205 1044 1114 +4 1041 1137 1044 1046 +4 1041 565 1045 1169 +4 1045 514 566 564 +4 1045 563 514 209 +4 1045 1094 209 194 +4 1045 209 197 194 +4 1045 1044 1169 1094 +4 1045 1114 1044 1094 +4 1045 209 514 197 +4 1134 1114 1046 205 +4 1134 192 1114 205 +4 1134 1114 1044 1046 +4 1134 1046 1044 1184 +4 354 1171 1141 304 +4 1159 1184 1134 1135 +4 1159 1134 1184 1046 +4 1105 1148 1166 1056 +4 1159 210 323 372 +4 1105 316 351 372 +4 1159 375 316 372 +4 1159 304 375 374 +4 1159 323 375 372 +4 1159 375 323 374 +4 1141 1116 1044 1184 +4 1141 304 1159 374 +4 1141 374 327 354 +4 354 1171 304 336 +4 1141 304 374 354 +4 1041 1042 1116 1137 +4 517 1041 1137 1042 +4 1041 546 495 527 +4 1041 546 566 495 +4 1041 1116 1169 1044 +4 1041 1116 1044 1137 +4 455 299 1068 491 +4 1064 283 246 217 +4 1064 1066 1127 1089 +4 1064 1066 1089 246 +4 1064 283 1181 229 +4 1064 283 229 246 +4 1064 1103 1127 1066 +4 1182 1065 1066 1106 +4 1182 1116 1044 1106 +4 1063 418 1181 473 +4 1065 1066 1106 1103 +4 1063 436 418 473 +4 1056 297 298 221 +4 1063 418 1179 1181 +4 1182 1044 1116 1184 +4 1159 1105 1166 210 +4 279 1166 298 1056 +4 295 1148 245 228 +4 1066 1182 1056 1065 +4 1148 375 304 355 +4 1105 1166 233 245 +4 1148 1066 1056 1089 +4 1148 1159 1141 304 +4 1148 1056 1184 1135 +4 1148 1184 1159 1135 +4 1148 1184 1056 1066 +4 1148 1184 1141 1159 +4 1080 1067 1146 1081 +4 1080 424 1146 1067 +4 1080 1146 424 461 +4 1080 424 1067 461 +4 1080 489 461 416 +4 1080 416 1145 1082 +4 1080 1145 416 1067 +4 1183 1038 1142 1145 +4 1080 1156 1081 1085 +4 1080 461 1067 416 +4 1086 1081 1146 1067 +4 1084 1129 1104 1087 +4 275 1153 247 222 +4 1154 1087 1088 1127 +4 1154 1064 1127 217 +4 1154 217 275 247 +4 1154 1087 1127 1104 +4 1154 281 247 223 +4 1154 281 217 247 +4 1084 443 453 409 +4 1153 1151 248 222 +4 1050 1153 1151 263 +4 1086 1087 1154 1129 +4 1086 1129 1154 223 +4 254 1086 223 1129 +4 1086 253 266 223 +4 1086 1085 1146 1081 +4 1086 1087 1085 1081 +4 1152 413 437 443 +4 1152 1102 1104 437 +4 1152 413 1102 437 +4 1152 1085 1104 1170 +4 569 1060 526 1047 +4 1128 523 510 570 +4 444 1152 413 1102 +4 1128 1170 1130 523 +4 570 1128 1060 1102 +4 1128 1104 1102 1107 +4 1128 1104 1107 1115 +4 1128 1127 1104 1115 +4 1126 1128 1150 1115 +4 1128 523 1060 1170 +4 1167 1080 462 1077 +4 1047 1162 1156 1060 +4 1167 462 489 417 +4 1167 448 1077 462 +4 1167 417 448 462 +4 1183 1147 273 250 +4 1178 1124 1047 1048 +4 1156 1085 1080 1077 +4 1156 1051 1133 1082 +4 1156 1122 1085 1170 +4 1156 1077 1152 1085 +4 1156 1152 1077 1060 +4 1156 1152 1060 1170 +4 1156 1085 1152 1170 +4 1131 1048 1113 318 +4 1124 1048 350 325 +4 1124 350 308 325 +4 1124 343 1048 325 +4 1124 308 343 325 +4 1124 1048 343 534 +4 1124 343 1162 534 +4 1124 339 1162 343 +4 1124 339 343 308 +4 1047 1124 1162 498 +4 1047 498 541 516 +4 1047 498 1162 526 +4 1047 498 526 541 +4 1178 1133 1156 1051 +4 1178 1170 1156 1162 +4 1139 306 332 340 +4 1139 1122 1178 1170 +4 1178 1081 1156 1122 +4 1178 1156 1081 1051 +4 1178 1081 1122 1051 +4 1178 1124 1051 1122 +4 1150 361 1149 1042 +4 1150 361 1042 322 +4 310 1150 1130 322 +4 1150 513 1130 322 +4 1150 1149 1115 1042 +4 1126 332 319 301 +4 1126 1149 1088 1127 +4 1126 1087 1122 1170 +4 1126 1127 1088 1087 +4 1153 1088 1154 1087 +4 1126 1153 1088 1151 +4 1139 1130 1126 1170 +4 1139 335 1124 1122 +4 1139 1162 1124 339 +4 1139 1124 1178 1122 +4 1139 1178 1124 1162 +4 1139 1130 1170 1162 +4 1139 339 1130 1162 +4 1049 350 303 335 +4 1147 220 1125 1175 +4 1153 263 253 222 +4 1153 1081 219 263 +4 1153 219 253 263 +4 1153 1086 1081 1087 +4 1153 1086 253 219 +4 1153 1081 1086 219 +4 1050 1151 1153 1122 +4 1050 1151 1122 306 +4 1050 1122 335 306 +4 1050 376 1151 306 +4 1050 335 376 306 +4 1050 335 320 376 +4 1049 357 330 320 +4 1147 250 1083 271 +4 1131 1052 1049 331 +4 1049 331 1052 357 +4 1049 303 357 320 +4 1049 1052 1172 357 +4 1049 303 331 357 +4 1125 288 1052 1099 +4 1125 220 288 249 +4 1125 288 1099 227 +4 1125 249 288 227 +4 1147 1172 1052 255 +4 1147 255 1052 277 +4 1147 224 1172 255 +4 1147 277 224 255 +4 1147 250 224 277 +4 1132 1131 1052 1049 +4 1038 1147 220 273 +4 1183 1147 1067 1083 +4 225 1183 1145 1038 +4 1183 1067 273 225 +4 1038 1108 1145 239 +4 1069 1155 1097 1119 +4 1143 428 410 477 +4 1069 1175 1133 1072 +4 1143 414 1043 469 +4 1143 1043 414 450 +4 1143 1108 1043 450 +4 1143 428 1108 446 +4 1143 428 446 414 +4 1143 1145 1108 428 +4 1143 439 463 414 +4 1109 1055 1125 1072 +4 1143 414 463 428 +4 1079 227 276 249 +4 1109 1055 1072 1071 +4 1098 1143 1043 469 +4 1173 1144 1075 1098 +4 1078 1168 1185 1140 +4 1079 218 274 276 +4 1079 276 274 249 +4 1098 408 468 439 +4 1073 470 420 431 +4 1185 285 1043 240 +4 1098 1043 1144 476 +4 1185 1140 1144 231 +4 1185 1140 231 280 +4 1185 286 1140 280 +4 1185 218 286 280 +4 1185 1165 1144 1140 +4 1078 276 241 286 +4 1078 1185 1079 218 +4 1078 286 1185 218 +4 1173 1098 1075 1111 +4 1078 276 1079 1091 +4 1054 341 1055 334 +4 1054 307 341 334 +4 1054 307 1099 341 +4 1132 1172 1147 1083 +4 1054 1125 1099 1091 +4 1054 342 1091 1099 +4 1054 342 1099 307 +4 1054 1091 342 321 +4 1054 342 307 321 +4 1123 1058 1059 356 +4 1054 353 307 334 +4 1054 307 353 321 +4 1110 1165 1078 1092 +4 1110 1092 1078 1091 +4 1123 353 1054 302 +4 1123 1101 360 356 +4 1053 1093 1058 317 +4 1053 1110 1111 1055 +4 1123 1058 1053 1059 +4 1123 1054 1053 334 +4 1123 302 1054 334 +4 1123 1110 1054 1091 +4 1123 1092 1110 1091 +4 1123 1053 1110 1120 +4 1123 1110 1053 1054 +4 1075 468 408 470 +4 1057 1058 1061 1059 +4 1073 1075 1074 470 +4 1163 1057 1062 1061 +4 395 1164 397 390 +4 1073 1118 1121 512 +4 1073 1118 553 504 +4 1073 1076 1118 504 +4 1073 553 1076 504 +4 1073 553 512 431 +4 1073 468 1096 1075 +4 1073 512 1096 431 +4 1073 468 1075 470 +4 1096 449 468 431 +4 1057 528 508 547 +4 1073 1075 1096 1095 +4 1073 1096 468 431 +4 1180 499 525 532 +4 1070 1053 1095 1111 +4 1097 449 1096 1119 +4 1097 1096 449 415 +4 1097 1119 445 449 +4 1097 445 415 449 +4 1097 1119 1155 445 +4 1095 1118 1075 1120 +4 1097 415 445 465 +4 1097 465 439 415 +4 1176 1095 1070 1053 +4 1070 1053 1111 1055 +4 1176 1070 1180 1093 +4 1070 1111 1095 1071 +4 1121 544 512 551 +4 1095 1111 1053 1120 +4 1069 1071 1070 1097 +4 1069 1142 1072 1071 +4 1070 1072 1055 1071 +4 1070 1055 1072 1161 +4 522 1180 1161 567 +4 1180 1093 1161 567 +4 1180 496 1093 567 +4 1180 568 1093 496 +4 1180 525 568 496 +4 1180 1161 1070 1119 +4 1176 1095 1180 1070 +4 1180 1070 1161 1093 +4 1142 440 1167 1082 +4 1183 1067 1147 250 +4 1142 1082 1145 440 +4 1174 1099 1125 1052 +4 1132 1051 1049 1172 +4 1174 341 1100 1055 +4 1174 1055 1054 341 +4 1174 1125 1054 1055 +4 1100 341 1052 331 +4 1100 1161 1072 1055 +4 1082 1132 1083 1051 +4 1131 1133 1113 1048 +4 1131 1048 1178 1133 +4 1131 1178 1048 1051 +4 1131 1133 1178 1051 +4 1131 350 1049 1051 +4 1131 1048 1124 1051 +4 1163 1164 1117 1120 +4 1163 1057 1061 1059 +4 1164 1074 1117 1075 +4 1117 1118 1062 1120 +4 1164 382 395 397 +4 1164 386 1144 1140 +4 1164 386 1140 397 +4 1164 1168 1140 1165 +4 1164 1140 1144 1165 +4 1163 1062 387 383 +4 1163 387 396 383 +4 1163 1062 1117 395 +4 1163 1117 1062 1120 +4 1163 396 1101 383 +4 1090 314 368 345 +4 1090 400 393 345 +4 1090 393 261 345 +4 1182 1044 1134 1114 +4 1182 1134 1044 1184 +4 1182 1114 1134 1112 +4 1177 1040 423 488 +4 1182 1136 1065 1112 +4 1158 215 373 18 +4 1158 373 1138 315 +4 1158 193 1046 1138 +4 1158 193 1138 215 +4 1158 1138 373 215 +4 1171 1066 1089 1149 +4 1171 1137 1141 1116 +4 1171 1141 1137 1042 +4 1171 1137 1116 1042 +4 1171 1141 1148 1184 +4 1171 1116 1141 1184 +4 1171 1116 1066 1149 +4 1171 1116 1149 1042 +4 1177 1157 411 467 +4 1177 1106 1157 467 +4 1177 1106 1182 1157 +4 1177 1157 1182 1112 +4 1063 1177 466 411 +4 1063 466 436 411 +4 1063 1181 1103 473 +4 435 1063 1177 466 +4 1177 488 435 466 +4 1177 411 488 466 +4 1105 351 371 267 +4 1105 371 292 267 +4 1105 292 371 245 +4 1105 326 1148 245 +4 1105 371 326 245 +4 1105 326 316 375 +4 1105 351 316 371 +4 1105 371 316 326 +4 1068 1064 1154 217 +4 1068 283 1064 217 +4 1068 283 281 237 +4 1068 1103 1064 1181 +4 1068 1129 1103 1181 +4 1068 1181 1064 283 +4 1068 1127 1154 1064 +4 1104 1068 1154 1129 +4 1068 281 1154 1129 +4 1160 494 1047 511 +4 1160 1133 1047 571 +4 1160 571 1047 494 +4 1160 1156 1047 1133 +4 1160 522 1133 571 +4 1160 522 571 494 +4 1069 1142 1175 1072 +4 1160 548 494 511 +4 1160 548 522 494 +4 1084 1146 1086 1085 +4 1084 1129 1086 1146 +4 1084 437 1152 1104 +4 1084 1104 1152 1085 +4 1084 412 1129 1146 +4 1132 1174 1052 1100 +4 1132 1052 1131 1100 +4 1174 1100 1072 1055 +4 1174 1072 1125 1055 +4 1174 1125 1072 1175 +4 1147 1174 1175 1125 +4 1132 1133 1131 1051 +4 1132 1147 1175 1083 +4 1183 1132 1175 1083 +4 1183 1082 1132 1083 +4 1183 1082 1080 1145 +4 1183 1145 1080 1067 +4 1183 1080 1082 1083 +4 1183 1067 1080 1083 +4 225 1183 1067 1145 +4 1109 249 1079 226 +4 287 1109 1108 226 +4 220 1109 287 249 +4 1109 1072 1125 1175 +4 1109 1071 1072 1175 +4 1109 1125 1038 1175 +4 1109 1125 1079 249 +4 1173 1144 1185 1165 +4 1173 1079 1078 1185 +4 1173 1185 1078 1165 +4 1173 1109 1079 1043 +4 1173 1098 1109 1043 +4 1173 1079 1185 1043 +4 1176 508 1093 568 +4 1176 1058 1053 1093 +4 1176 508 1058 1093 +4 1057 505 1058 528 +4 1057 1095 1121 1176 +4 1176 525 493 508 +4 1121 544 493 525 +4 1121 551 493 544 +4 1121 1095 1096 1119 +4 1073 468 470 431 +4 1121 544 1096 512 +4 1121 1118 1095 1120 +4 1121 1180 1176 1095 +4 1095 1121 1073 1118 +4 1073 1075 1095 1118 +4 1073 1076 1075 1118 +4 1073 420 1076 475 +4 1069 1155 1160 1167 +4 1082 1160 1167 1069 +4 1069 1133 1161 1072 +4 1069 1155 1142 1097 +4 1069 1167 1142 1155 +4 1069 1160 1155 1161 +4 1069 1133 1160 1161 +4 1186 1187 599 641 +4 108 640 682 737 +4 1188 1189 1190 870 +4 1186 641 910 903 +4 1191 1192 740 721 +4 1193 1194 1195 578 +4 1196 1197 1198 1199 +4 1200 1201 1202 713 +4 1203 1204 1205 1206 +4 1207 391 1208 399 +4 1204 1206 1209 838 +4 877 805 165 9 +4 1210 1036 993 916 +4 1211 1200 713 745 +4 1212 1213 1214 1215 +4 1186 599 1187 653 +4 1216 1217 1013 961 +4 1218 1219 1220 1221 +4 1194 663 858 911 +4 1222 1223 1224 1225 +4 1214 753 704 751 +4 1226 993 1210 943 +4 132 898 639 603 +4 1211 1034 958 1035 +4 141 929 877 631 +4 1227 1218 787 729 +4 1228 1229 1230 913 +4 1231 1232 1233 938 +4 1234 894 897 822 +4 1235 1236 1237 1238 +4 1239 600 645 652 +4 1196 1198 1197 1240 +4 1241 1242 1224 1243 +4 43 388 661 606 +4 1244 1245 1246 670 +4 1247 1248 946 973 +4 1249 854 1250 802 +4 1251 920 863 826 +4 1222 947 1252 986 +4 1193 674 677 578 +4 1241 1253 1227 1242 +4 1254 1255 1256 801 +4 992 889 185 928 +4 1186 653 589 641 +4 1216 953 1024 1013 +4 1188 824 870 926 +4 1257 878 175 848 +4 1196 1240 1258 1247 +4 1259 1260 1205 1215 +4 1261 625 639 584 +4 1262 764 727 701 +4 1202 144 750 996 +4 1263 908 79 403 +4 1264 402 1206 386 +4 1248 977 999 731 +4 1265 758 760 711 +4 887 636 1206 1209 +4 1266 1267 1197 1265 +4 1268 1006 957 1004 +4 1210 804 810 990 +4 1269 939 1270 984 +4 1271 582 604 648 +4 1228 1230 1229 1272 +4 980 1273 995 1274 +4 1275 686 1276 1277 +4 389 719 774 75 +4 1278 805 814 797 +4 1279 1278 883 633 +4 1280 769 780 717 +4 981 710 157 955 +4 1281 646 1282 586 +4 1210 916 827 857 +4 1283 873 1226 1284 +4 1223 868 1252 1000 +4 726 1253 1227 741 +4 1285 1244 1286 670 +4 1287 1288 1006 975 +4 778 1275 736 694 +4 1289 851 1230 913 +4 155 961 1013 712 +4 1275 686 1277 778 +4 1201 1213 1290 1291 +4 1213 1291 773 405 +4 1234 897 894 853 +4 1292 654 911 902 +4 123 634 887 885 +4 1293 576 642 644 +4 1247 1223 1294 1272 +4 1295 1296 1297 932 +4 1211 1202 1296 1035 +4 1298 1229 1272 1294 +4 1231 1232 1256 795 +4 1299 729 1227 699 +4 1300 613 577 669 +4 1301 789 691 786 +4 1191 785 720 698 +4 1196 1198 1262 1199 +4 1300 595 1280 613 +4 1302 836 864 889 +4 1303 622 772 637 +4 1190 1304 1261 1305 +4 844 1226 1025 856 +4 930 11 804 169 +4 1210 810 1011 990 +4 394 5 636 887 +4 396 1264 382 398 +4 127 893 850 648 +4 1247 973 933 1009 +4 1302 186 957 889 +4 1306 666 1307 573 +4 1196 1262 1308 1199 +4 1241 1309 741 730 +4 1188 870 905 831 +4 776 618 632 106 +4 113 662 769 112 +4 1210 1036 857 990 +4 1310 1231 1233 811 +4 1231 811 172 967 +4 1311 596 843 673 +4 1312 1280 780 784 +4 1313 1301 618 724 +4 1196 1308 1262 1247 +4 1314 384 395 390 +4 1210 827 912 857 +4 1310 1256 1235 1232 +4 810 169 1011 990 +4 1315 955 966 710 +4 1316 396 395 387 +4 1269 697 1217 732 +4 997 392 401 85 +4 825 1317 875 1229 +4 1266 1318 1319 779 +4 1320 1271 648 893 +4 1321 862 839 923 +4 1196 1240 1247 1248 +4 1246 647 1214 751 +4 1322 1323 1324 1325 +4 1326 917 849 876 +4 1234 837 907 853 +4 1327 709 1191 721 +4 1281 922 1186 859 +4 1280 662 769 717 +4 1328 1277 1329 1330 +4 1300 656 1187 1220 +4 1331 766 813 744 +4 1230 649 667 603 +4 1252 1000 868 872 +4 1332 1223 933 951 +4 1241 1032 937 1030 +4 992 889 957 185 +4 1333 1257 848 830 +4 1334 956 1273 995 +4 1207 1335 1208 1336 +4 1196 1247 1262 1248 +4 142 750 143 996 +4 1195 1337 1313 615 +4 1291 392 405 383 +4 384 1316 395 387 +4 1210 827 916 856 +4 1296 1202 1291 996 +4 823 1320 1338 1339 +4 962 1316 1208 387 +4 1286 714 629 602 +4 1201 1213 1291 703 +4 1326 1340 1271 1341 +4 1201 763 719 703 +4 1214 393 635 660 +4 1244 1201 1212 1215 +4 1342 880 1010 845 +4 1211 989 144 958 +4 1289 1325 1324 575 +4 1300 1187 656 653 +4 1229 840 913 861 +4 1316 1296 1290 1343 +4 1241 969 1032 1030 +4 1214 404 660 606 +4 1286 695 762 743 +4 394 78 5 887 +4 1344 914 1292 839 +4 1264 398 1213 385 +4 1316 1296 1259 1290 +4 1319 768 1318 597 +4 125 601 876 630 +4 633 843 673 139 +4 1345 1235 1346 1192 +4 1218 787 1347 1303 +4 1348 1210 1233 943 +4 1026 966 159 722 +4 120 121 607 800 +4 1267 1266 1318 1293 +4 1317 1349 1229 1321 +4 1293 644 615 576 +4 1301 640 618 771 +4 1241 755 1016 969 +4 1350 1268 1288 1302 +4 1186 1187 903 842 +4 1351 770 638 718 +4 1347 1303 725 605 +4 1187 599 625 656 +4 1261 1352 1230 898 +4 1285 1319 1293 642 +4 1211 958 1202 1035 +4 1291 1202 750 996 +4 1234 1263 897 853 +4 772 637 110 725 +4 1316 1314 1290 1215 +4 613 1353 579 1280 +4 1350 860 1186 922 +4 1354 1334 1274 1005 +4 1355 1001 960 941 +4 726 1253 1242 1227 +4 887 636 1209 634 +4 1228 1189 866 870 +4 1336 1208 948 1014 +4 654 1194 911 663 +4 1356 718 1351 638 +4 155 1013 154 712 +4 1357 1238 1249 1250 +4 1191 740 1315 693 +4 1226 1345 931 965 +4 1357 919 1250 854 +4 1312 697 733 757 +4 1296 1035 1202 996 +4 1200 1358 735 760 +4 1209 634 849 885 +4 1317 835 1294 865 +4 1300 1347 595 669 +4 1347 1280 769 708 +4 1347 662 1280 595 +4 1356 709 718 778 +4 1347 769 662 655 +4 1310 808 1249 794 +4 1210 804 857 817 +4 1279 1346 1357 1238 +4 1359 596 573 608 +4 1360 1283 833 863 +4 1266 1293 1319 1318 +4 1246 657 1214 647 +4 1316 1290 1314 382 +4 1313 618 1301 628 +4 1015 927 888 1294 +4 1342 834 880 890 +4 982 745 989 145 +4 1361 1362 1338 1340 +4 1316 1290 1259 1215 +4 1319 762 716 619 +4 1363 1364 623 582 +4 1320 828 1271 893 +4 1021 730 969 153 +4 1296 1208 1012 962 +4 1209 636 590 634 +4 1365 1202 1201 1290 +4 1295 1260 1365 1366 +4 43 44 388 606 +4 1364 623 678 574 +4 396 1264 398 1213 +4 1337 1293 615 668 +4 1193 921 1321 923 +4 1304 1218 1303 1219 +4 1352 639 625 879 +4 1302 864 978 186 +4 1253 726 1322 687 +4 1280 780 784 717 +4 1352 829 1230 898 +4 1243 952 1016 970 +4 1347 725 775 605 +4 1307 1236 665 598 +4 1231 795 803 811 +4 1262 1248 764 701 +4 1322 1239 1323 737 +4 1282 906 882 841 +4 1300 1187 1186 1367 +4 882 138 906 614 +4 1357 1210 856 827 +4 1302 836 889 900 +4 964 799 1022 171 +4 1278 631 814 805 +4 1287 1368 1288 975 +4 1351 116 638 770 +4 1345 1276 1329 955 +4 1359 1238 1279 1369 +4 1311 673 614 596 +4 1279 1369 1250 1278 +4 1273 940 1362 980 +4 1303 772 788 725 +4 1244 1246 1212 783 +4 1193 923 858 921 +4 1337 1292 1293 668 +4 1248 933 1243 1009 +4 1334 1366 1200 1358 +4 1266 728 779 689 +4 1342 1010 1370 950 +4 1295 1365 1211 1200 +4 668 1194 615 1337 +4 632 768 776 105 +4 772 637 622 110 +4 1291 405 392 773 +4 1241 702 1243 755 +4 1370 880 865 179 +4 911 654 663 128 +4 1363 1371 1285 1341 +4 1361 1257 1333 1338 +4 1315 781 693 722 +4 1372 1373 1312 1280 +4 1369 797 1250 1278 +4 1207 384 391 399 +4 1358 1339 1267 1362 +4 1314 1263 1207 390 +4 1278 883 929 832 +4 1275 1276 686 736 +4 1281 859 906 920 +4 1350 874 1302 836 +4 1310 1254 819 794 +4 1366 1361 1295 1260 +4 1319 1318 1293 644 +4 1248 1240 977 731 +4 1265 945 991 1005 +4 1318 776 632 768 +4 1248 754 999 970 +4 1188 1288 1374 900 +4 1211 713 144 745 +4 1286 629 714 743 +4 1241 972 1222 937 +4 1226 844 1284 873 +4 993 189 1025 856 +4 1226 856 1210 993 +4 1240 731 701 742 +4 1338 1355 1362 1257 +4 1344 823 914 862 +4 127 128 654 902 +4 1194 1337 578 615 +4 126 630 125 876 +4 1284 844 1025 963 +4 141 631 877 805 +4 1230 667 620 603 +4 1309 699 730 747 +4 1241 741 702 730 +4 1265 991 711 956 +4 183 872 1000 976 +4 682 1323 600 1239 +4 1241 702 755 730 +4 1228 870 1352 1189 +4 158 710 966 955 +4 158 966 710 722 +4 720 1191 693 785 +4 1282 906 841 920 +4 1316 1207 1208 384 +4 865 180 1015 968 +4 1342 834 1317 1370 +4 1374 846 928 872 +4 1225 1189 1228 1272 +4 1301 786 706 771 +4 1198 728 758 700 +4 1244 1286 783 695 +4 1311 646 1307 573 +4 1191 1315 1192 1232 +4 843 139 882 673 +4 1233 799 964 170 +4 1363 576 1293 668 +4 1326 1340 1333 867 +4 1211 1273 745 989 +4 1274 1362 1338 1355 +4 191 916 1036 857 +4 1233 811 1022 799 +4 42 661 43 402 +4 1333 1205 1234 1335 +4 1206 838 1263 908 +4 1214 388 404 606 +4 1268 1270 979 942 +4 1306 638 1356 1351 +4 1255 1256 813 766 +4 1359 1279 1311 596 +4 638 782 115 658 +4 772 682 622 737 +4 1331 744 792 698 +4 782 114 115 658 +4 1231 777 1256 723 +4 1296 1291 1343 949 +4 1211 713 1200 1202 +4 125 634 849 601 +4 1214 385 1213 400 +4 1265 711 991 748 +4 392 1343 997 401 +4 1271 648 893 630 +4 391 7 998 82 +4 1196 1375 1298 1247 +4 1251 841 863 920 +4 1288 975 944 1006 +4 1304 1190 1261 656 +4 882 1376 1282 841 +4 74 400 774 75 +4 1213 719 1291 703 +4 1292 850 604 127 +4 126 630 876 893 +4 662 655 769 112 +4 1345 1346 1284 1330 +4 1226 931 954 965 +4 1250 802 166 812 +4 1278 883 633 683 +4 1374 944 1252 976 +4 1276 740 710 722 +4 1226 1357 856 873 +4 814 631 650 119 +4 141 631 805 9 +4 1348 1029 938 965 +4 1281 859 617 643 +4 191 11 930 990 +4 44 404 388 606 +4 1327 1236 1331 1255 +4 1328 1353 1372 1377 +4 1287 1378 1288 1367 +4 116 749 626 117 +4 1233 964 943 1011 +4 816 163 801 777 +4 1331 698 1255 766 +4 1309 953 1021 1030 +4 1264 1314 1205 1215 +4 1365 1290 1201 1215 +4 1241 702 1253 1243 +4 1194 610 858 663 +4 1241 937 1309 1030 +4 1186 910 617 859 +4 1253 764 765 687 +4 1210 796 810 804 +4 1255 813 1256 801 +4 1291 997 142 752 +4 1207 998 886 1007 +4 1200 1244 1201 734 +4 634 887 885 838 +4 1266 705 779 728 +4 1258 946 1248 1240 +4 1207 1208 998 948 +4 1244 783 1212 688 +4 1314 1335 1207 1234 +4 1228 1352 1261 1189 +4 1190 1261 1189 1305 +4 1372 1280 1312 1377 +4 1269 1002 981 939 +4 1261 639 1352 898 +4 1288 957 992 889 +4 1224 1324 1242 1305 +4 1188 1187 1190 1367 +4 1201 767 1213 719 +4 1257 878 1001 988 +4 1188 1190 1368 1367 +4 1231 967 1026 938 +4 1233 810 1210 796 +4 1288 1302 889 900 +4 1188 1367 1368 1288 +4 1277 709 1356 778 +4 993 189 856 190 +4 844 1025 963 188 +4 393 635 45 4 +4 1290 1291 1213 405 +4 1191 720 1256 698 +4 1374 1288 928 846 +4 187 978 864 186 +4 1197 1337 1267 1293 +4 1202 763 750 713 +4 1214 591 647 657 +4 1333 1205 1204 1234 +4 1202 958 144 996 +4 1316 1259 1314 1215 +4 1244 1245 1215 1214 +4 1206 386 394 403 +4 1316 1343 1290 383 +4 1327 1236 598 580 +4 1359 1278 633 585 +4 1312 1280 1218 780 +4 962 1296 1343 949 +4 1188 1368 1374 1288 +4 1301 727 1323 706 +4 1289 649 901 659 +4 1258 1265 1354 945 +4 1290 405 1213 389 +4 1377 675 611 658 +4 1312 690 1218 1373 +4 638 115 782 718 +4 1377 1356 658 782 +4 1239 622 645 600 +4 1300 1221 1281 627 +4 1226 954 993 943 +4 1194 592 663 654 +4 175 878 988 176 +4 1206 402 394 386 +4 1336 959 1007 884 +4 641 681 135 903 +4 391 82 1019 399 +4 1310 811 1233 799 +4 1250 812 805 797 +4 815 122 684 806 +4 1327 1331 1236 580 +4 1202 1035 958 996 +4 1266 735 1358 760 +4 1212 1246 751 790 +4 1291 773 392 752 +4 389 774 400 75 +4 1188 1368 1190 1189 +4 1188 824 860 900 +4 1239 1323 600 652 +4 1262 687 1322 727 +4 178 1017 880 1010 +4 1295 1027 1257 941 +4 1355 950 1023 1010 +4 1313 1318 776 632 +4 1342 1317 834 890 +4 1239 645 581 620 +4 1207 1263 1234 853 +4 1291 703 773 752 +4 1354 974 1023 950 +4 1001 871 960 177 +4 1243 970 1016 755 +4 393 74 400 753 +4 1297 1014 1027 932 +4 1213 389 400 385 +4 1244 1215 1245 1260 +4 1287 1217 1373 1216 +4 1277 1192 1327 709 +4 597 619 716 104 +4 823 1320 925 1338 +4 1206 908 1263 403 +4 1286 1246 714 602 +4 1273 738 760 696 +4 1257 175 959 848 +4 1347 775 655 605 +4 1377 611 746 658 +4 1376 1379 1330 1346 +4 1187 1352 852 926 +4 1289 909 659 901 +4 1243 715 970 755 +4 1347 655 595 669 +4 1332 1294 1247 1223 +4 1280 784 1377 717 +4 1241 741 1253 702 +4 1288 889 846 900 +4 1377 658 746 782 +4 1210 796 804 817 +4 1231 1256 777 816 +4 806 684 8 122 +4 1356 638 593 658 +4 1191 1232 1256 693 +4 1320 1371 1339 1293 +4 1343 401 392 383 +4 1214 774 704 753 +4 1202 958 713 144 +4 1223 847 1294 899 +4 1370 865 1294 968 +4 1365 1201 1244 1215 +4 1204 924 1209 849 +4 1246 647 751 602 +4 1230 649 132 851 +4 1204 1263 1206 897 +4 1321 1344 1349 1337 +4 1293 576 615 668 +4 1338 1355 871 892 +4 1257 1027 1336 959 +4 178 880 1017 179 +4 865 888 1015 180 +4 1318 789 776 705 +4 1358 1339 1362 1371 +4 1313 1197 1318 1337 +4 1318 632 587 644 +4 1241 1243 1253 1242 +4 1287 1309 1299 1219 +4 1292 604 668 654 +4 1332 1223 1247 933 +4 911 654 128 902 +4 1193 677 1194 578 +4 1359 1236 1331 580 +4 843 633 673 596 +4 814 805 631 119 +4 1356 709 1351 718 +4 1268 1270 1360 1378 +4 1280 613 676 579 +4 1283 1284 1380 881 +4 1187 903 852 681 +4 1196 1375 1197 1349 +4 1323 588 640 652 +4 1193 1349 1195 1194 +4 191 930 857 990 +4 1310 819 807 794 +4 1244 1260 1245 1341 +4 1287 1381 1217 1216 +4 1306 579 1353 675 +4 1250 812 877 805 +4 1227 692 726 741 +4 1299 729 699 759 +4 714 629 102 743 +4 1259 1296 1365 1290 +4 1200 734 713 696 +4 1286 714 1246 783 +4 1265 711 1273 956 +4 77 773 405 76 +4 1209 838 1206 887 +4 1303 726 1242 692 +4 1312 1217 697 757 +4 1273 738 982 956 +4 1287 1381 1216 975 +4 1313 776 618 632 +4 1310 808 807 799 +4 1278 877 929 631 +4 132 901 851 649 +4 1289 1193 1195 612 +4 852 903 134 681 +4 1300 1186 1281 1221 +4 1328 1312 1372 1275 +4 1275 694 733 736 +4 1303 707 726 788 +4 1287 1373 1367 1219 +4 1322 707 1239 737 +4 1304 1347 577 680 +4 806 161 8 684 +4 1351 116 770 749 +4 1287 1373 1217 1378 +4 1214 774 753 400 +4 123 636 887 634 +4 123 887 636 5 +4 1287 1217 1381 1378 +4 732 961 155 712 +4 606 1245 657 1214 +4 1204 838 924 897 +4 1264 651 590 606 +4 1289 840 1193 909 +4 1374 992 944 976 +4 1278 814 631 650 +4 1279 633 843 596 +4 1357 1249 1210 912 +4 1249 854 802 912 +4 1231 1256 693 723 +4 802 854 167 912 +4 1279 1357 1376 855 +4 141 805 877 9 +4 394 78 887 403 +4 1237 120 607 800 +4 633 883 139 140 +4 1233 964 1029 943 +4 1236 1254 1331 1255 +4 1351 709 749 770 +4 1239 600 682 622 +4 1197 1313 1199 1337 +4 1294 888 899 847 +4 1196 1354 1258 1240 +4 1287 1219 1299 1373 +4 1287 1299 1216 1373 +4 1287 1219 1368 1222 +4 1323 640 600 652 +4 1303 637 772 725 +4 1322 756 726 707 +4 1262 687 727 764 +4 1201 1291 1290 1202 +4 1265 760 1273 711 +4 1316 1314 1207 384 +4 1363 582 671 604 +4 1336 1014 948 1007 +4 1192 721 709 686 +4 598 1327 749 1351 +4 1310 1235 1254 794 +4 1231 967 160 1026 +4 1359 1237 1236 1238 +4 804 817 168 857 +4 1210 1036 916 857 +4 1299 1216 1373 1217 +4 1240 748 1265 991 +4 1196 1247 1298 1308 +4 1342 1370 1317 1354 +4 1304 1305 1219 1242 +4 1268 957 1288 1302 +4 1376 1330 1283 1346 +4 1299 1216 1217 712 +4 1299 1373 1312 1217 +4 1355 1354 1344 1274 +4 964 799 171 170 +4 1246 751 714 602 +4 1299 1373 1218 690 +4 1257 959 1336 848 +4 1206 1314 1263 1205 +4 1303 605 581 637 +4 1380 833 881 864 +4 1380 1004 978 942 +4 1264 590 1206 661 +4 1363 621 1285 642 +4 668 1363 671 604 +4 1273 995 940 980 +4 1211 713 1202 958 +4 1212 751 704 790 +4 1345 955 1329 931 +4 1236 665 598 580 +4 1210 857 804 990 +4 1231 777 723 816 +4 1250 166 854 896 +4 1249 802 817 912 +4 172 1022 967 811 +4 1233 1022 964 799 +4 1037 793 10 803 +4 1255 1256 766 698 +4 1328 1353 1306 1379 +4 1321 1292 1344 1194 +4 1195 588 1323 652 +4 1229 1228 821 913 +4 1267 1337 1344 1293 +4 1266 1267 1358 1293 +4 815 122 609 684 +4 1254 798 800 815 +4 1231 781 723 693 +4 1319 779 1318 768 +4 1230 620 667 575 +4 1380 864 874 833 +4 625 852 134 681 +4 1243 715 755 702 +4 136 910 641 135 +4 607 1331 1237 800 +4 1271 893 876 630 +4 1285 1286 1366 695 +4 1328 1330 1353 1379 +4 1201 1202 763 703 +4 1200 1366 1244 734 +4 1321 839 1194 923 +4 1328 1306 1277 1379 +4 1372 1378 1373 1221 +4 981 739 157 710 +4 1206 1263 386 403 +4 173 886 998 1007 +4 173 998 886 7 +4 1359 1236 1279 1238 +4 1357 1250 1249 854 +4 1297 1014 1336 1027 +4 80 390 907 853 +4 111 637 605 725 +4 111 110 637 725 +4 1368 944 975 986 +4 1197 1266 1198 1318 +4 1318 632 597 768 +4 1323 682 640 737 +4 130 659 610 909 +4 1307 666 598 665 +4 1356 782 638 658 +4 1328 1329 1275 1330 +4 1226 931 1284 954 +4 1202 703 750 763 +4 1319 1293 1358 1371 +4 1326 1333 1203 1204 +4 604 1320 850 1292 +4 1372 1217 1373 1378 +4 43 388 402 661 +4 1311 1376 1346 1379 +4 1376 1357 873 855 +4 1380 1003 187 881 +4 1244 1215 1212 1214 +4 1326 1271 1364 1341 +4 391 886 998 7 +4 1201 1215 1290 1213 +4 1331 685 792 744 +4 1348 1029 1233 938 +4 806 161 744 813 +4 1317 1375 1354 1370 +4 1194 677 610 663 +4 1338 1320 925 869 +4 1289 901 913 840 +4 719 405 773 76 +4 1290 405 389 383 +4 1334 1265 956 995 +4 1361 1260 1203 1205 +4 1355 941 960 980 +4 1271 582 648 630 +4 1326 1364 1203 1341 +4 125 601 849 876 +4 1212 790 688 783 +4 714 602 102 629 +4 1322 1324 1308 1325 +4 1301 588 618 640 +4 1225 1272 1228 821 +4 1321 1349 1194 1337 +4 835 1229 899 861 +4 393 4 753 635 +4 1347 655 662 595 +4 1262 1240 701 742 +4 1331 664 607 580 +4 1304 620 581 624 +4 1249 1210 817 796 +4 1312 780 690 784 +4 1005 1354 945 974 +4 1231 1037 793 160 +4 1377 1353 579 675 +4 1310 1348 1210 1233 +4 1250 877 1278 805 +4 638 1306 593 666 +4 1251 1330 1376 1379 +4 1282 882 906 614 +4 1299 759 699 747 +4 175 959 884 1007 +4 1206 636 394 402 +4 1208 1297 1336 1335 +4 1314 395 397 390 +4 1206 887 908 403 +4 1204 917 924 849 +4 1264 1213 1214 385 +4 1206 394 887 403 +4 1264 661 1206 402 +4 1207 907 390 853 +4 604 127 850 648 +4 1289 851 913 901 +4 1357 1210 827 912 +4 1278 585 672 607 +4 1250 832 1278 877 +4 1262 1240 1248 701 +4 1204 1206 838 897 +4 1292 127 604 654 +4 1257 988 1001 941 +4 1286 619 583 629 +4 1274 1267 1339 1362 +4 1198 1199 1301 691 +4 1223 1224 933 1008 +4 1372 1217 1312 1373 +4 1217 1013 961 712 +4 1351 598 116 749 +4 1226 1025 993 954 +4 1372 1350 1221 1353 +4 1380 881 187 864 +4 1228 1352 870 829 +4 1248 701 1240 731 +4 1372 1221 1350 1378 +4 1277 1236 1327 1192 +4 633 843 139 883 +4 1268 1006 1288 957 +4 1372 1270 1217 1378 +4 1005 1334 1274 934 +4 1265 1005 991 956 +4 1313 1301 1198 1199 +4 883 683 929 140 +4 1278 929 683 631 +4 1376 873 1283 820 +4 1273 745 982 738 +4 1273 940 982 989 +4 146 711 147 956 +4 146 738 711 956 +4 1376 1360 1330 1251 +4 1282 614 906 643 +4 1237 607 672 580 +4 1250 805 1278 797 +4 1315 1026 781 722 +4 1239 622 682 737 +4 1188 831 1374 1252 +4 1227 787 1218 1303 +4 1288 928 846 889 +4 1378 1360 1350 1251 +4 1317 1370 865 1294 +4 1269 710 761 739 +4 1201 1291 1202 703 +4 1365 1244 1260 1215 +4 1275 1277 1356 778 +4 1327 709 721 698 +4 1237 120 814 650 +4 1369 802 1250 818 +4 1327 698 1331 792 +4 1329 1277 1192 1330 +4 1278 1237 814 650 +4 1316 382 395 396 +4 1332 1031 936 1033 +4 1304 1239 581 620 +4 1381 1378 1217 1270 +4 778 1275 694 1356 +4 154 712 1013 747 +4 762 103 104 619 +4 1248 754 970 715 +4 1286 670 1246 602 +4 1258 1033 1354 1370 +4 1334 1267 1274 1362 +4 1194 677 592 615 +4 947 1222 1252 1223 +4 1223 1224 1008 972 +4 1225 868 1223 847 +4 1309 953 1216 1021 +4 901 659 649 131 +4 1339 1344 823 914 +4 1230 1324 620 575 +4 1312 690 733 784 +4 1237 607 120 650 +4 1231 1315 781 693 +4 1281 646 1379 1282 +4 1359 1307 1236 665 +4 1278 814 1237 797 +4 1229 875 825 861 +4 1195 652 1325 612 +4 1250 797 802 812 +4 1187 681 625 599 +4 133 898 879 639 +4 136 641 910 617 +4 1298 1199 1308 1325 +4 1323 640 682 600 +4 1321 1194 1344 1337 +4 1303 787 775 725 +4 1195 628 588 612 +4 1244 783 688 734 +4 1240 731 700 748 +4 1285 1286 583 670 +4 1257 830 878 848 +4 1298 1199 1325 1349 +4 772 622 682 109 +4 1225 847 1223 899 +4 1258 946 987 973 +4 1288 1302 957 889 +4 125 849 634 885 +4 1207 390 1263 853 +4 1271 876 601 630 +4 1299 757 759 712 +4 1312 733 694 784 +4 1324 1261 1228 1230 +4 1230 851 901 649 +4 1299 1219 1309 1227 +4 1324 1325 1323 575 +4 1213 773 1291 719 +4 1208 1012 962 1014 +4 835 1317 1294 1229 +4 1229 835 875 861 +4 1229 861 825 921 +4 615 1195 628 1313 +4 1193 594 674 612 +4 927 1015 888 181 +4 1312 733 1275 694 +4 1286 629 583 670 +4 597 716 768 104 +4 1318 1197 1267 1293 +4 132 901 649 131 +4 1021 730 153 747 +4 1233 964 1011 170 +4 1235 1192 1236 1346 +4 1250 832 877 896 +4 1209 849 924 885 +4 1297 932 1296 1012 +4 1195 1349 1325 1199 +4 1322 1323 756 737 +4 1313 618 628 587 +4 1355 960 1023 980 +4 1367 1221 1219 1373 +4 1359 665 1236 580 +4 1316 1208 1296 962 +4 1314 1234 1207 1263 +4 1302 978 957 186 +4 1285 1293 1319 1371 +4 1223 1008 947 972 +4 1193 1195 674 578 +4 1294 927 888 847 +4 1283 1284 1226 1346 +4 1307 1351 1236 598 +4 1380 978 187 1003 +4 1312 694 1377 784 +4 1209 1326 1203 1204 +4 1201 767 719 763 +4 1350 1367 1288 1378 +4 1218 708 1347 787 +4 1226 1348 965 943 +4 8 684 161 744 +4 1249 808 818 794 +4 1348 1315 985 938 +4 1311 843 1282 673 +4 1254 819 798 801 +4 1327 626 792 685 +4 1372 1221 1280 1353 +4 1249 1238 1369 1250 +4 930 169 804 990 +4 1357 854 1249 912 +4 1312 1377 1280 784 +4 1364 1245 623 574 +4 1211 144 713 958 +4 1195 1194 1337 578 +4 1193 610 674 659 +4 1268 1004 935 1006 +4 1193 610 1194 677 +4 1194 1292 592 654 +4 1193 1325 1195 1349 +4 1313 1198 1301 789 +4 1190 1352 1261 656 +4 844 963 881 188 +4 1356 778 718 694 +4 963 1003 881 188 +4 1284 1020 931 984 +4 1251 1372 1378 1270 +4 1187 641 681 599 +4 1311 614 646 596 +4 1299 747 1216 712 +4 1188 1252 1374 1368 +4 1376 904 863 841 +4 1372 1330 1275 1270 +4 1237 814 120 800 +4 1278 929 883 683 +4 1289 840 909 901 +4 1261 625 1352 639 +4 1268 1302 1380 1004 +4 1304 1261 624 656 +4 1381 935 1024 975 +4 159 966 158 722 +4 801 720 163 162 +4 1361 1338 1333 1340 +4 1245 1246 670 657 +4 1273 1295 1200 1362 +4 1334 1200 1366 1362 +4 1354 1023 1355 950 +4 1295 1200 1362 1366 +4 1275 1217 1269 697 +4 1239 622 581 645 +4 801 777 163 720 +4 816 164 163 777 +4 1249 817 1210 912 +4 1188 915 860 824 +4 1243 952 1032 1016 +4 625 134 852 879 +4 1239 622 1303 581 +4 1202 713 750 144 +4 1259 1297 1365 1296 +4 1295 1296 1211 1365 +4 1343 1291 1290 383 +4 838 1209 885 634 +4 1291 752 142 750 +4 1207 406 384 390 +4 664 121 815 800 +4 664 815 122 609 +4 664 122 815 121 +4 1254 800 1331 815 +4 1295 983 1034 932 +4 1214 1213 774 400 +4 1203 1341 1245 1260 +4 1214 393 385 400 +4 1343 1291 997 949 +4 1342 892 1338 823 +4 1214 635 393 753 +4 1214 385 393 404 +4 1292 839 914 902 +4 1271 849 601 876 +4 178 1010 845 177 +4 178 1010 880 845 +4 1350 1268 1378 1288 +4 1309 699 1227 741 +4 981 739 156 157 +4 981 739 994 156 +4 1328 1356 1377 694 +4 1269 981 1002 955 +4 1345 1329 1284 931 +4 1329 955 1269 1002 +4 1333 848 867 830 +4 1001 176 988 878 +4 1001 871 176 878 +4 1001 176 871 177 +4 391 81 406 886 +4 391 81 886 7 +4 1254 1310 819 1256 +4 999 754 149 150 +4 999 970 754 150 +4 731 999 754 149 +4 647 102 751 602 +4 647 101 751 102 +4 1295 983 1027 941 +4 1018 401 84 85 +4 1018 997 401 85 +4 1244 1286 1246 783 +4 108 682 109 737 +4 865 968 179 180 +4 1326 1364 1271 849 +4 1332 973 1258 936 +4 1226 931 1345 1284 +4 1251 922 1281 920 +4 1372 1270 1251 1330 +4 1239 1305 1303 1242 +4 1342 1355 1010 950 +4 1285 576 1293 1371 +4 1262 1243 1248 1308 +4 1287 1268 1006 1288 +4 1334 1265 995 1005 +4 142 997 6 752 +4 1291 750 142 996 +4 868 182 183 1000 +4 1227 741 729 692 +4 868 1000 927 182 +4 1225 1294 1223 1272 +4 1268 1360 1380 1302 +4 42 402 394 636 +4 42 402 636 661 +4 1333 830 1338 1257 +4 1209 636 1206 590 +4 1273 995 982 940 +4 1287 1381 1268 1378 +4 994 739 732 156 +4 994 155 732 961 +4 994 156 732 155 +4 1251 920 1281 1282 +4 1305 1272 1224 1324 +4 1323 771 706 737 +4 126 893 127 648 +4 126 630 893 648 +4 1345 1348 985 965 +4 1327 792 1331 685 +4 1344 1320 1293 1292 +4 1197 1266 1318 1267 +4 1370 834 865 880 +4 1231 967 1022 811 +4 723 164 816 777 +4 1256 801 816 795 +4 1231 160 781 1026 +4 927 971 181 182 +4 1196 1298 1375 1349 +4 1225 1294 1272 899 +4 927 182 1000 971 +4 1268 979 935 1004 +4 1266 689 760 758 +4 1229 1289 1230 913 +4 1204 1209 924 838 +4 1378 1360 1251 1270 +4 1360 833 1283 1380 +4 1347 769 1280 662 +4 625 133 879 639 +4 625 879 133 134 +4 1363 642 1285 576 +4 1320 648 1271 604 +4 1292 911 839 902 +4 1198 700 1240 742 +4 183 872 976 184 +4 1248 701 715 764 +4 1247 1308 1224 1272 +4 1204 1263 1234 1205 +4 1295 1361 1297 1260 +4 1355 1001 1257 871 +4 1264 590 661 606 +4 1364 623 1245 1341 +4 1291 142 997 996 +4 1309 1021 1216 747 +4 1303 772 707 788 +4 130 659 909 131 +4 1226 965 954 943 +4 1280 662 676 595 +4 1233 964 1022 938 +4 1275 736 686 778 +4 1380 1004 1302 978 +4 618 724 107 106 +4 1247 933 1248 1009 +4 1374 1288 846 900 +4 1294 971 951 1015 +4 1347 669 577 680 +4 1248 933 1224 1243 +4 1273 711 760 738 +4 982 738 146 956 +4 982 738 145 146 +4 647 635 753 100 +4 1214 388 385 404 +4 1316 396 387 383 +4 1214 404 393 660 +4 1206 1314 1205 1264 +4 1282 843 882 673 +4 1250 877 812 896 +4 1278 805 877 631 +4 1376 1346 1283 1357 +4 132 898 133 639 +4 1270 1380 1284 942 +4 984 1269 1329 1270 +4 1241 1016 1032 969 +4 393 404 45 660 +4 1275 736 733 697 +4 1380 978 1003 942 +4 1360 1284 1270 1380 +4 1228 1272 1324 1230 +4 1301 1323 640 771 +4 1294 968 1015 1031 +4 1322 726 756 687 +4 1299 699 1309 747 +4 1269 1217 1270 939 +4 632 776 106 105 +4 1319 642 597 644 +4 825 1317 1229 1321 +4 776 618 106 724 +4 1249 818 1369 794 +4 1311 673 1282 614 +4 1250 802 797 818 +4 607 1331 800 664 +4 1278 585 650 631 +4 141 929 683 140 +4 141 631 683 929 +4 1381 1217 1028 939 +4 1275 1269 1329 1276 +4 1300 1281 589 627 +4 1186 617 910 641 +4 1195 628 1313 1301 +4 1261 639 1230 603 +4 1323 727 756 706 +4 1294 835 899 888 +4 1350 1186 1281 922 +4 191 1036 916 190 +4 835 1229 1294 899 +4 45 44 660 404 +4 136 617 859 137 +4 136 617 910 859 +4 1207 1336 948 1007 +4 1230 132 649 603 +4 1264 1314 382 397 +4 1304 1220 1218 1219 +4 1216 1024 953 975 +4 1241 1032 972 937 +4 1225 1189 1224 1222 +4 1257 1027 959 988 +4 1360 1283 1284 1380 +4 668 1194 592 615 +4 1338 823 892 869 +4 997 6 392 85 +4 997 392 6 752 +4 633 683 883 140 +4 1359 580 1237 672 +4 1377 593 675 658 +4 1229 1289 1193 1325 +4 1005 1354 1265 945 +4 1247 1248 973 1009 +4 1370 865 968 179 +4 1258 1354 1033 974 +4 1277 1236 1192 1346 +4 143 750 144 996 +4 1291 750 1202 703 +4 1284 1020 984 942 +4 1372 1251 1350 1353 +4 1376 1360 1283 1330 +4 1275 761 1276 736 +4 1377 579 676 675 +4 1270 1284 984 942 +4 1188 870 1352 926 +4 1217 994 961 939 +4 1281 627 1353 616 +4 1360 1251 1270 1330 +4 1359 1311 1279 1236 +4 1279 1346 1376 1357 +4 1277 1351 1356 709 +4 1276 710 1315 722 +4 1359 1307 1311 1236 +4 1335 1336 1333 1361 +4 1295 1362 980 941 +4 1273 982 995 956 +4 1264 661 402 388 +4 386 1314 397 390 +4 1264 1203 1215 1205 +4 1214 591 657 606 +4 1206 661 636 402 +4 1334 956 1265 1273 +4 1313 587 628 615 +4 1320 1338 1340 869 +4 1262 691 1198 742 +4 1325 652 1323 575 +4 1198 728 700 742 +4 1359 608 672 585 +4 1223 927 868 971 +4 1284 1020 963 954 +4 1283 873 844 891 +4 42 636 394 5 +4 108 771 107 640 +4 1244 1341 1245 670 +4 1331 698 766 744 +4 1210 1011 943 990 +4 1233 799 810 796 +4 1363 1293 1292 668 +4 1214 660 591 606 +4 1209 924 838 885 +4 80 81 907 406 +4 80 406 907 390 +4 1245 623 574 670 +4 1264 382 398 397 +4 1206 838 908 887 +4 1374 944 1368 1252 +4 1368 1190 1189 1219 +4 1299 1219 1218 1373 +4 1374 928 992 184 +4 124 634 123 885 +4 124 125 634 885 +4 1359 672 1278 585 +4 1359 580 672 608 +4 877 165 812 896 +4 877 812 165 805 +4 1359 1237 1278 672 +4 1316 1259 1297 1335 +4 1208 1014 962 948 +4 1310 1232 1348 1233 +4 1213 389 398 396 +4 1271 601 582 630 +4 1229 921 1193 840 +4 1195 1323 1325 652 +4 1195 578 1337 615 +4 974 1274 1005 1354 +4 1322 756 1323 727 +4 187 881 1003 188 +4 1273 745 738 696 +4 762 103 629 743 +4 762 629 103 619 +4 762 104 716 619 +4 993 916 190 856 +4 993 190 916 1036 +4 1226 856 993 1025 +4 980 1295 940 1362 +4 792 685 118 744 +4 792 118 685 117 +4 792 685 626 117 +4 1244 1246 1286 670 +4 1207 884 1336 1007 +4 1244 1285 1286 1366 +4 618 107 724 771 +4 1285 1358 1319 1366 +4 1289 1272 1324 1325 +4 1274 1355 1338 1339 +4 1319 1293 642 644 +4 1363 1341 1285 623 +4 618 640 107 771 +4 1310 1232 1235 1348 +4 1231 1026 1315 938 +4 1037 793 160 10 +4 930 168 804 11 +4 930 857 804 168 +4 930 804 857 990 +4 1331 607 1237 580 +4 781 1026 159 722 +4 781 1026 160 159 +4 1291 752 750 703 +4 1203 1209 1204 1206 +4 989 144 145 745 +4 1295 980 983 941 +4 1273 711 738 956 +4 1227 787 692 729 +4 1195 1301 1325 1323 +4 1322 1242 1303 726 +4 1313 1318 1198 789 +4 1304 1305 1239 620 +4 1245 606 1264 1214 +4 1320 1371 1271 1340 +4 1274 1267 1344 1339 +4 695 1285 762 1319 +4 1188 1374 905 900 +4 1287 1006 1268 1381 +4 868 971 927 1000 +4 868 1000 183 872 +4 1241 1016 1243 1032 +4 1317 1321 825 862 +4 1015 927 1294 971 +4 1197 1318 1337 1293 +4 1359 1331 1237 580 +4 814 650 120 119 +4 1231 1022 1233 811 +4 793 10 803 164 +4 1231 1037 172 803 +4 1261 584 639 603 +4 1353 1350 1221 1281 +4 1277 1379 1236 1346 +4 1269 710 981 955 +4 974 1274 934 1005 +4 1370 968 1031 1033 +4 1223 1000 1252 947 +4 1033 1354 1370 950 +4 4 753 635 100 +4 393 753 4 74 +4 1016 755 151 152 +4 1016 152 969 755 +4 1016 970 151 755 +4 1225 899 821 895 +4 1231 816 723 164 +4 1216 747 1013 712 +4 1021 153 154 747 +4 1021 154 1013 747 +4 882 139 138 673 +4 1348 985 965 938 +4 882 138 614 673 +4 1231 1256 816 795 +4 1210 993 1036 943 +4 1233 808 799 796 +4 1345 1315 1276 955 +4 646 1281 1379 616 +4 174 1007 884 173 +4 174 1007 175 884 +4 116 638 770 115 +4 1291 719 773 703 +4 962 387 83 84 +4 1342 880 1370 1010 +4 392 1343 1291 997 +4 1376 863 904 820 +4 1186 589 617 641 +4 1360 833 874 863 +4 1302 186 889 864 +4 1228 1324 1272 1305 +4 611 113 746 114 +4 611 746 658 114 +4 1377 782 746 694 +4 597 768 105 104 +4 1313 776 1318 789 +4 1285 1293 576 642 +4 1363 671 576 668 +4 1214 774 1213 704 +4 1310 799 807 795 +4 1257 830 871 878 +4 1193 1321 1194 923 +4 1193 923 1194 858 +4 130 858 610 129 +4 129 128 911 663 +4 129 911 858 663 +4 1225 1272 1223 1224 +4 970 151 715 150 +4 1241 755 1243 1016 +4 970 715 754 150 +4 1266 1334 760 1358 +4 1274 1338 1362 1339 +4 1310 807 819 795 +4 992 928 185 184 +4 1211 1296 1034 1035 +4 166 812 165 896 +4 1279 1250 1369 1238 +4 1197 1199 1313 1198 +4 1248 1243 1224 1308 +4 1264 1213 1290 1215 +4 74 400 753 774 +4 731 999 149 977 +4 1248 1009 1243 970 +4 731 149 148 977 +4 1278 633 585 683 +4 574 1364 679 678 +4 1198 789 705 728 +4 1257 959 175 988 +4 1295 1257 1361 1362 +4 1188 824 905 870 +4 1217 961 1028 939 +4 1248 754 715 701 +4 1363 1364 1341 623 +4 1339 1362 1371 1340 +4 1310 1232 1231 795 +4 1193 909 610 659 +4 1319 779 716 791 +4 575 1289 612 667 +4 1265 956 995 1005 +4 1195 588 1301 1323 +4 1303 637 725 605 +4 1269 697 732 739 +4 1315 710 966 722 +4 1327 698 792 749 +4 1304 624 1261 1305 +4 1268 979 1381 935 +4 1261 624 656 584 +4 1251 1282 841 920 +4 1328 1377 1312 694 +4 844 1226 1284 1025 +4 1300 595 613 669 +4 1347 725 1303 775 +4 1250 812 166 896 +4 802 912 167 817 +4 1214 753 393 400 +4 1282 586 614 643 +4 919 1279 1250 832 +4 1255 798 813 801 +4 1331 626 685 609 +4 166 802 854 167 +4 1360 863 1251 1376 +4 1360 863 1376 1283 +4 1380 978 1302 864 +4 1380 864 187 978 +4 1190 1189 1261 1352 +4 1187 656 653 599 +4 1281 586 627 616 +4 1218 780 1280 708 +4 1187 681 641 903 +4 969 152 153 730 +4 969 730 755 152 +4 1241 755 969 730 +4 1314 1206 1263 386 +4 1295 1034 1296 932 +4 1329 955 1276 1269 +4 77 752 392 773 +4 77 773 392 405 +4 1317 835 865 875 +4 1193 674 1195 612 +4 575 1230 1289 667 +4 1248 970 1243 715 +4 1310 1233 1231 1232 +4 1345 985 1315 955 +4 810 804 169 990 +4 1231 816 164 803 +4 1310 1233 1249 808 +4 1015 180 888 181 +4 1245 1264 606 651 +4 113 769 662 717 +4 1281 922 859 920 +4 1211 1365 1296 1202 +4 1332 968 1294 1031 +4 927 971 1015 181 +4 1363 1292 1293 1371 +4 1314 1207 384 390 +4 991 148 748 147 +4 1317 1229 1349 1375 +4 991 748 148 977 +4 991 147 711 956 +4 1310 1249 1235 794 +4 655 775 111 605 +4 655 111 775 112 +4 655 775 769 112 +4 746 114 782 658 +4 1280 1377 579 676 +4 1281 1353 1379 616 +4 1268 957 1302 1004 +4 1254 800 798 809 +4 598 626 116 749 +4 1329 1277 1276 1192 +4 1348 1232 1315 938 +4 1186 922 910 859 +4 1299 757 690 759 +4 1280 579 1377 1353 +4 1302 957 978 1004 +4 1332 1375 1258 1247 +4 6 392 77 752 +4 1257 988 175 878 +4 1211 144 989 745 +4 1363 1341 1364 1271 +4 1273 989 982 745 +4 1305 1272 1189 1224 +4 1229 1228 1272 821 +4 1352 639 879 898 +4 1223 1222 1224 972 +4 1276 1315 740 722 +4 1254 1237 1331 800 +4 1251 1376 863 1282 +4 1229 840 1289 913 +4 1229 913 821 861 +4 1332 1294 1223 951 +4 1332 1247 1258 973 +4 1275 1276 1329 1277 +4 1345 1235 1238 1346 +4 682 1323 1239 737 +4 1329 931 1002 984 +4 647 751 101 100 +4 647 753 751 100 +4 1275 1269 1276 761 +4 1187 852 1352 625 +4 910 903 641 135 +4 844 856 1025 189 +4 844 189 1025 188 +4 1259 1260 1297 1205 +4 1245 1209 1264 590 +4 1332 951 973 1031 +4 1213 773 719 405 +4 1377 1356 782 694 +4 177 1355 1010 845 +4 1370 1033 1017 968 +4 1310 1238 1235 1249 +4 1351 116 598 638 +4 1351 709 770 718 +4 1225 831 866 870 +4 1194 578 677 615 +4 1222 947 986 972 +4 1344 914 839 862 +4 1210 943 1036 990 +4 1237 797 814 800 +4 1327 1331 626 685 +4 1356 718 782 694 +4 1332 1294 951 1031 +4 933 1243 952 972 +4 1268 1350 1360 1302 +4 1216 747 1021 1013 +4 1269 981 994 939 +4 1252 976 1000 872 +4 1037 10 172 803 +4 1022 811 171 799 +4 1356 718 638 782 +4 1233 810 799 170 +4 1345 1329 1192 1330 +4 1311 596 646 573 +4 1380 864 1302 874 +4 1372 1275 1312 1217 +4 1284 1025 954 963 +4 1332 1294 1370 1375 +4 1213 719 389 405 +4 1290 389 1213 396 +4 1291 996 997 949 +4 1248 731 999 754 +4 1224 1272 1308 1324 +4 1280 595 676 613 +4 1289 1195 1193 1325 +4 1225 899 1272 821 +4 625 1261 1352 656 +4 1275 761 736 697 +4 1372 1373 1280 1221 +4 103 102 629 743 +4 1212 714 1246 790 +4 1332 1370 1258 1375 +4 1188 1302 1288 900 +4 1207 1234 1335 1336 +4 1203 1260 1245 1215 +4 80 79 390 853 +4 884 886 173 1007 +4 1300 1221 1220 1367 +4 617 137 643 859 +4 1186 1367 1187 860 +4 1214 751 647 753 +4 1264 1290 1314 1215 +4 1246 602 670 657 +4 393 45 635 660 +4 792 626 749 117 +4 1332 1247 1298 1375 +4 685 609 684 744 +4 685 684 118 744 +4 157 710 158 955 +4 850 648 893 1320 +4 1207 884 1007 886 +4 1213 398 389 385 +4 1264 402 386 388 +4 1343 392 1291 383 +4 1214 753 647 635 +4 1193 858 610 909 +4 1225 831 870 1188 +4 1241 1222 1309 937 +4 772 110 622 109 +4 1239 772 622 737 +4 1187 625 1352 656 +4 1331 766 1255 813 +4 908 887 78 403 +4 1244 1246 1245 1214 +4 79 908 78 403 +4 1207 1336 1208 948 +4 1211 1273 1200 745 +4 191 857 1036 990 +4 168 817 912 857 +4 168 817 167 912 +4 930 11 169 990 +4 660 44 606 404 +4 1200 734 1201 713 +4 1227 1241 1242 1222 +4 1286 714 783 743 +4 906 138 137 643 +4 906 643 614 138 +4 1281 643 1282 906 +4 906 137 859 643 +4 1376 1283 863 820 +4 1279 1236 1311 1346 +4 1226 954 1284 1025 +4 1357 856 873 827 +4 1250 854 166 802 +4 1254 798 1255 801 +4 1187 852 625 681 +4 1377 1356 593 658 +4 1187 852 915 926 +4 1196 1199 1298 1349 +4 1261 1230 639 898 +4 1188 1252 1368 1189 +4 1285 623 1341 670 +4 1355 871 845 177 +4 1295 1034 983 940 +4 1333 1335 1234 1336 +4 118 684 8 744 +4 1359 1237 1369 1278 +4 1313 618 776 724 +4 1342 1355 1338 892 +4 1269 761 697 739 +4 1372 1353 1280 1377 +4 806 161 684 744 +4 1297 1012 1296 1208 +4 751 102 714 602 +4 957 185 889 186 +4 1360 1284 1283 1330 +4 1288 992 957 1006 +4 1262 1253 1322 687 +4 1319 762 695 716 +4 1316 1314 1259 1335 +4 391 998 1019 82 +4 1209 838 887 634 +4 947 1222 1223 972 +4 1317 875 834 862 +4 909 659 901 131 +4 1229 821 1272 899 +4 1294 888 865 835 +4 1294 1015 865 888 +4 1300 1186 1187 653 +4 1342 823 1338 1339 +4 1239 707 772 737 +4 1318 705 776 768 +4 1198 758 1265 700 +4 1319 597 1318 644 +4 751 1212 1214 1246 +4 1301 706 1323 771 +4 1299 690 1218 729 +4 1269 994 1217 939 +4 1358 1366 1371 1362 +4 389 405 719 76 +4 1206 1263 838 897 +4 389 719 75 76 +4 1241 972 1032 952 +4 1327 1236 1191 1192 +4 1359 573 1311 1307 +4 1233 1011 810 170 +4 607 121 664 800 +4 1319 768 597 716 +4 1193 858 1194 610 +4 1285 583 623 670 +4 1223 933 951 1008 +4 1322 756 727 687 +4 970 715 151 755 +4 1241 1032 1243 952 +4 1290 1291 405 383 +4 1241 1243 972 952 +4 1241 1243 1224 972 +4 632 597 768 105 +4 1317 825 875 862 +4 1276 761 686 736 +4 1268 1360 1270 1380 +4 1282 673 882 614 +4 1268 1380 1270 942 +4 1269 739 981 710 +4 1186 1187 842 860 +4 1323 706 756 737 +4 1196 1197 1375 1354 +4 1193 610 677 674 +4 1195 588 652 612 +4 1241 1224 1222 972 +4 925 823 1338 869 +4 805 631 119 9 +4 1278 607 1237 650 +4 1310 1249 1233 1210 +4 1278 672 1237 607 +4 1228 1189 1261 1305 +4 1283 1226 1357 1346 +4 1214 660 635 591 +4 1301 628 618 588 +4 108 771 640 737 +4 1323 640 771 737 +4 772 109 682 737 +4 907 886 406 81 +4 384 1316 387 1208 +4 1334 995 934 1005 +4 982 745 145 738 +4 1258 1240 1265 945 +4 1258 973 987 936 +4 610 663 129 858 +4 130 610 858 909 +4 1201 719 1213 703 +4 1225 1252 1223 868 +4 135 134 903 681 +4 1214 635 647 591 +4 1355 1257 1001 941 +4 1304 680 577 624 +4 1224 1242 1189 1305 +4 1357 827 854 912 +4 1287 1216 1299 1309 +4 991 748 711 147 +4 1361 1297 1260 1205 +4 1019 82 83 399 +4 1225 831 895 866 +4 1226 1348 1345 965 +4 1186 599 653 641 +4 1251 841 1282 863 +4 1210 912 817 857 +4 1333 1338 830 867 +4 175 884 959 848 +4 1338 871 830 892 +4 770 115 638 718 +4 1254 798 819 809 +4 1381 1270 1217 939 +4 1374 928 184 872 +4 1280 662 1377 676 +4 1328 1372 1312 1377 +4 1381 1024 1216 975 +4 766 162 801 813 +4 766 720 801 162 +4 766 744 161 813 +4 766 161 162 813 +4 1327 626 1331 580 +4 1195 674 578 612 +4 1274 1267 1354 1344 +4 1198 789 1318 705 +4 1313 789 1301 724 +4 1322 756 707 737 +4 1301 1323 588 640 +4 172 171 1022 811 +4 1231 172 1037 967 +4 1231 1233 1022 938 +4 1254 809 819 794 +4 1256 693 723 777 +4 1231 1022 967 938 +4 1327 721 1191 698 +4 731 148 748 977 +4 1325 652 575 612 +4 1344 1337 1194 1292 +4 1246 714 751 790 +4 1290 389 396 383 +4 1212 714 790 783 +4 1231 693 1256 1232 +4 1310 1233 808 799 +4 810 1011 169 170 +4 963 1380 881 1003 +4 1306 1356 1277 1351 +4 1248 973 1009 946 +4 764 715 1248 1243 +4 1231 816 803 795 +4 1233 1011 1210 810 +4 1225 821 866 895 +4 1254 1256 819 801 +4 1225 821 1228 866 +4 1231 781 1315 1026 +4 1331 685 744 609 +4 1233 943 1210 1011 +4 1278 585 607 650 +4 1256 819 801 795 +4 1364 678 623 582 +4 1336 1007 959 1014 +4 1246 657 647 602 +4 1286 629 670 602 +4 1192 740 721 686 +4 775 725 111 605 +4 1225 1228 1189 866 +4 1225 831 868 895 +4 735 1319 791 1266 +4 1266 735 689 791 +4 1264 1203 1245 1215 +4 1291 392 997 752 +4 1213 400 389 774 +4 1213 704 719 767 +4 1213 704 774 719 +4 1213 774 389 719 +4 1264 1290 396 382 +4 1264 396 1290 1213 +4 1343 1018 997 401 +4 1326 1333 1204 822 +4 1316 1208 1297 1296 +4 1316 1290 396 383 +4 735 1319 1266 1358 +4 1245 1341 623 670 +4 1316 382 1314 395 +4 1343 997 1018 949 +4 962 1296 949 1012 +4 1296 1035 996 949 +4 1316 1296 1343 962 +4 1343 383 387 401 +4 1343 84 1018 401 +4 1343 387 84 401 +4 1343 949 1018 962 +4 1266 779 791 689 +4 1343 962 1018 84 +4 1343 387 962 84 +4 1336 1014 959 1027 +4 1316 387 1343 383 +4 1316 395 1314 384 +4 1207 1234 907 853 +4 1333 1336 1234 894 +4 1263 79 390 403 +4 1336 837 894 884 +4 1336 894 848 884 +4 1336 959 884 848 +4 1207 948 998 1007 +4 1264 1209 1206 590 +4 1207 837 884 886 +4 1206 887 394 636 +4 1207 837 1336 884 +4 1207 1208 384 399 +4 1244 1212 1246 1214 +4 1264 1215 1214 1213 +4 1206 661 590 636 +4 386 1314 390 1263 +4 1263 403 390 386 +4 1207 837 1234 1336 +4 1263 79 908 853 +4 1263 390 79 853 +4 1263 853 838 897 +4 1263 908 838 853 +4 1208 948 1019 998 +4 1208 1019 391 998 +4 1208 391 1019 399 +4 962 1316 387 1343 +4 1208 387 384 399 +4 1208 962 387 83 +4 1208 387 399 83 +4 1208 962 1019 948 +4 1208 1019 962 83 +4 1208 399 1019 83 +4 1266 779 1319 791 +4 1266 1265 1198 758 +4 1204 897 1234 1263 +4 1264 382 1314 1290 +4 590 1245 679 651 +4 1245 1264 651 590 +4 1209 590 679 634 +4 1209 601 849 634 +4 1204 1234 897 822 +4 1300 1186 1221 1367 +4 1364 1271 849 601 +4 1244 688 1201 734 +4 1209 679 601 634 +4 1363 1285 621 623 +4 1286 629 762 619 +4 1286 762 629 743 +4 1365 1244 1366 1260 +4 1319 779 768 716 +4 1297 1014 932 1012 +4 751 1212 704 1214 +4 1286 783 695 743 +4 1285 1244 670 1341 +4 1296 996 1291 949 +4 1266 1265 1197 1198 +4 1212 1246 714 783 +4 1361 1338 1362 1257 +4 1326 1340 867 869 +4 1259 1335 1314 1205 +4 1358 1267 1339 1371 +4 735 1319 695 791 +4 695 734 783 1244 +4 695 734 1244 1366 +4 1366 735 695 734 +4 1297 1012 1208 1014 +4 1257 871 1001 878 +4 1338 871 1257 830 +4 1245 1214 1246 657 +4 1204 1205 1206 1263 +4 1258 1240 1354 1265 +4 1266 689 758 728 +4 1326 917 867 822 +4 1317 1294 1229 1375 +4 1355 960 1001 871 +4 1257 941 1027 988 +4 1326 1204 917 822 +4 1267 1293 1339 1371 +4 1363 1271 582 604 +4 1361 1333 1203 1340 +4 1285 1371 1319 1358 +4 1363 1271 1364 582 +4 1320 850 828 893 +4 1292 127 654 902 +4 1245 670 574 657 +4 1285 1366 1319 695 +4 1292 850 127 902 +4 1363 621 582 623 +4 1197 1354 1265 1267 +4 1341 1260 1340 1366 +4 604 1320 1363 1271 +4 1337 615 1293 644 +4 1342 1355 892 845 +4 668 1363 604 1292 +4 1334 1273 1200 1362 +4 1240 700 1265 748 +4 1371 1366 1341 1340 +4 1371 1366 1340 1362 +4 1326 1203 1340 1341 +4 1326 849 1271 876 +4 1271 828 876 893 +4 1271 1340 1371 1341 +4 1292 668 592 654 +4 1292 914 850 902 +4 1266 705 1198 1318 +4 1253 1308 1224 1243 +4 1332 1370 968 1031 +4 1304 1347 680 605 +4 1195 1194 1349 1337 +4 1196 1197 1199 1349 +4 1194 1292 1337 668 +4 1194 592 1292 668 +4 1194 663 592 677 +4 654 1194 1292 911 +4 1194 839 1292 911 +4 1194 839 911 923 +4 1194 911 858 923 +4 1355 960 871 177 +4 1355 1362 1257 941 +4 1344 1293 1337 1292 +4 862 1342 823 890 +4 1317 865 1370 834 +4 1240 700 731 742 +4 1318 779 705 768 +4 1258 1247 946 973 +4 1342 1010 1355 845 +4 1370 880 179 1017 +4 1326 867 1333 822 +4 1363 621 642 576 +4 1197 1199 1349 1337 +4 1320 1371 1363 1271 +4 1320 1339 1371 1340 +4 1320 828 925 869 +4 1338 871 1355 1257 +4 1342 1354 1355 950 +4 1355 871 892 845 +4 1355 1010 1023 960 +4 177 1355 960 1010 +4 1197 1198 1265 1240 +4 1319 716 695 791 +4 1267 1344 1339 1293 +4 1262 764 1253 687 +4 1334 995 1274 934 +4 1295 1211 1034 940 +4 1358 1293 1267 1371 +4 735 1319 1366 695 +4 1274 1023 1354 974 +4 1197 1344 1267 1337 +4 1319 1366 1358 735 +4 1266 735 760 689 +4 1265 758 711 748 +4 1313 776 789 724 +4 1265 700 758 748 +4 1266 760 1265 758 +4 1318 597 632 644 +4 1313 1197 1198 1318 +4 1319 619 597 642 +4 1319 597 619 716 +4 1285 642 621 583 +4 1285 1371 1358 1366 +4 1285 583 621 623 +4 1239 1305 1324 620 +4 1239 772 1303 622 +4 1301 786 727 706 +4 1262 1325 1308 1199 +4 1301 786 691 727 +4 1301 724 789 786 +4 1301 618 724 771 +4 1301 724 786 771 +4 1262 691 1301 1199 +4 1289 1324 1272 1230 +4 1342 834 1370 880 +4 1247 933 1223 1224 +4 1247 1224 1223 1272 +4 1229 825 1321 921 +4 1229 1272 1294 899 +4 1195 1337 1349 1199 +4 1195 628 1301 588 +4 1243 1262 764 1253 +4 1222 1223 1225 1252 +4 933 1243 972 1224 +4 1322 1303 1239 707 +4 1289 1230 851 901 +4 1300 1218 1220 1221 +4 1223 868 927 847 +4 1325 1323 1301 1199 +4 1230 851 132 898 +4 1230 898 132 603 +4 1230 639 898 603 +4 1324 1261 1305 1228 +4 1230 851 898 829 +4 1243 1262 1248 764 +4 1197 1344 1354 1267 +4 1368 1252 944 986 +4 1239 707 1303 772 +4 1299 1217 1312 757 +4 1303 726 692 788 +4 764 715 1243 1253 +4 1218 1280 1373 1221 +4 1332 933 973 951 +4 1196 1298 1199 1308 +4 1268 1378 1360 1350 +4 1196 1198 1240 742 +4 1227 692 1242 726 +4 1243 970 1009 952 +4 1253 741 726 702 +4 715 1253 702 1243 +4 1253 715 765 764 +4 1243 1009 933 952 +4 1266 705 1318 779 +4 1188 1374 831 905 +4 1352 879 829 898 +4 1227 787 1303 692 +4 1374 831 905 872 +4 1225 831 1252 868 +4 1223 971 1000 947 +4 1225 831 1188 1252 +4 1241 1309 969 1030 +4 1252 976 944 986 +4 1288 1350 1302 1188 +4 1225 847 899 895 +4 1252 947 1000 976 +4 1252 868 831 872 +4 1252 947 976 986 +4 1266 760 1334 1265 +4 835 1317 1229 875 +4 1262 1253 1243 1308 +4 1262 1301 691 727 +4 1294 968 865 1015 +4 1248 701 731 754 +4 1262 1199 1198 691 +4 1033 1258 936 1332 +4 1298 1272 1229 1325 +4 1332 933 1247 973 +4 1308 1272 1325 1324 +4 1224 972 933 1008 +4 1322 1303 707 726 +4 1223 971 868 1000 +4 1187 903 915 852 +4 1266 1198 705 728 +4 1241 1242 1222 1224 +4 1368 937 986 975 +4 1294 1015 951 1031 +4 1298 1349 1229 1375 +4 1197 1349 1375 1344 +4 1370 179 968 1017 +4 1332 1370 1031 1033 +4 1321 1344 1292 839 +4 1228 1230 1261 1352 +4 1321 1292 1194 839 +4 1321 862 1344 839 +4 1240 748 991 977 +4 1240 731 748 977 +4 1196 1262 1240 1248 +4 1354 1334 1005 1265 +4 1266 758 1198 728 +4 1240 991 1265 945 +4 1240 991 945 977 +4 1240 987 946 977 +4 1240 987 977 945 +4 1248 946 1009 970 +4 1248 977 1240 946 +4 1248 999 977 946 +4 1258 1248 1247 1240 +4 1248 970 999 946 +4 818 1254 800 1369 +4 1278 877 832 929 +4 1278 683 585 631 +4 1250 854 832 896 +4 1235 1255 1236 1192 +4 1210 916 993 856 +4 1250 919 832 854 +4 1226 844 873 856 +4 1254 1235 1369 794 +4 1226 1345 1238 1346 +4 1310 1238 1249 1210 +4 1233 1029 964 938 +4 1310 811 799 795 +4 1226 1210 1348 943 +4 1269 732 1217 994 +4 1197 1265 1354 1240 +4 1327 598 1236 1351 +4 1280 1377 662 717 +4 1269 732 994 739 +4 1310 1256 1232 795 +4 1345 1238 1235 1348 +4 1191 721 740 693 +4 1191 1232 1192 1255 +4 1306 1377 593 675 +4 1231 967 1037 160 +4 1191 1192 1236 1255 +4 1254 794 1369 818 +4 1231 723 781 160 +4 1256 777 816 801 +4 1256 720 693 777 +4 1191 740 1192 1315 +4 1310 1210 1348 1238 +4 1327 1191 1236 1255 +4 638 1306 666 1351 +4 1256 813 766 801 +4 1254 1331 798 815 +4 1256 766 698 720 +4 1327 1191 1255 698 +4 1256 801 720 777 +4 1256 801 766 720 +4 1191 1232 1255 1256 +4 1331 806 744 813 +4 1331 744 806 684 +4 684 1331 609 815 +4 1331 744 684 609 +4 1331 1255 798 813 +4 1331 798 806 813 +4 1331 580 626 609 +4 1307 666 1351 598 +4 1331 806 798 815 +4 1331 609 664 580 +4 800 1331 815 664 +4 684 1331 815 806 +4 1331 664 609 815 +4 1306 1277 1307 1351 +4 1351 638 598 666 +4 1284 931 1020 954 +4 1277 1192 709 686 +4 984 1269 1002 1329 +4 1348 1233 1232 938 +4 1283 873 1284 844 +4 1328 1312 1275 694 +4 1191 1315 1232 693 +4 1348 1233 1029 943 +4 1315 693 740 722 +4 1315 966 1026 722 +4 1315 1026 966 938 +4 1348 1029 965 943 +4 1345 985 955 931 +4 1315 966 985 938 +4 1315 955 985 966 +4 1279 832 919 855 +4 1281 906 859 643 +4 1312 1217 1275 697 +4 1376 863 1282 841 +4 1186 903 910 842 +4 1306 1353 1377 675 +4 882 1376 841 904 +4 1235 1256 1255 1232 +4 1359 1331 1236 1237 +4 1270 979 942 984 +4 1279 1238 1236 1346 +4 1284 844 963 881 +4 881 1283 844 891 +4 1188 926 915 824 +4 1284 963 1020 942 +4 881 1283 1284 844 +4 1376 820 904 855 +4 1360 1350 874 1302 +4 1279 919 1357 855 +4 1376 1357 1283 873 +4 1282 646 614 586 +4 1279 1376 843 855 +4 1283 881 1380 833 +4 1300 595 1347 1280 +4 646 1281 616 586 +4 1251 1281 1379 1282 +4 665 1359 573 608 +4 1251 1379 1376 1282 +4 1287 1309 975 1216 +4 1306 573 646 616 +4 1328 1275 1372 1330 +4 1345 1192 1346 1330 +4 1279 1346 1311 1376 +4 1235 1346 1236 1238 +4 1327 1255 1331 698 +4 1359 608 585 596 +4 1277 1351 1327 1236 +4 1310 807 808 794 +4 1254 1255 1235 1256 +4 1372 1270 1275 1217 +4 656 1304 1220 577 +4 1334 1265 760 1273 +4 1353 627 1221 613 +4 1353 579 627 613 +4 1353 616 627 579 +4 1306 666 573 616 +4 1306 573 1307 646 +4 1306 1353 579 616 +4 1328 1277 1275 1329 +4 1302 836 874 864 +4 836 1350 900 1302 +4 1334 1266 1265 1267 +4 1216 1021 953 1013 +4 1268 979 1004 942 +4 1381 1006 935 975 +4 1381 979 1270 939 +4 1329 955 1002 931 +4 1334 1266 1267 1358 +4 1380 963 1284 942 +4 1380 1003 963 942 +4 963 1380 1284 881 +4 1279 843 1311 596 +4 1283 1357 1226 873 +4 1268 1381 1006 935 +4 1269 1002 939 984 +4 1312 697 1275 733 +4 1299 757 1312 690 +4 1269 994 981 739 +4 1217 961 994 732 +4 1277 1327 1351 709 +4 1270 939 979 984 +4 1368 1288 975 944 +4 1251 1379 1281 1353 +4 1350 1281 1251 922 +4 1360 874 1350 826 +4 1281 906 1282 920 +4 1309 969 1021 730 +4 1381 1028 979 939 +4 1268 1378 1381 1270 +4 1188 926 1187 915 +4 1216 1013 1024 961 +4 1300 1220 1187 1367 +4 1216 1013 1217 712 +4 1360 874 1380 1302 +4 1368 937 1222 986 +4 1299 759 690 729 +4 1217 757 732 697 +4 1217 732 757 712 +4 1217 961 732 712 +4 1377 717 784 694 +4 1377 675 676 611 +4 1347 708 769 775 +4 1377 611 676 662 +4 1377 113 611 662 +4 1377 113 662 717 +4 1377 746 717 694 +4 1377 746 611 113 +4 1377 746 113 717 +4 1303 581 622 637 +4 1303 787 725 788 +4 1303 692 787 788 +4 1227 1241 1222 1309 +4 1299 1309 1216 747 +4 1241 969 1309 730 +4 1188 1187 1367 860 +4 1218 1373 1219 1221 +4 1287 1309 1222 937 +4 1222 1242 1219 1189 +4 1347 708 775 787 +4 1347 769 655 775 +4 613 1353 1280 1221 +4 1218 1280 1347 708 +4 1300 577 1347 669 +4 1374 1252 831 872 +4 937 1368 1287 975 +4 1187 915 842 860 +4 1299 1218 1227 729 +4 1304 1190 656 1220 +4 1219 1305 1189 1242 +4 1367 1221 1373 1378 +4 1288 992 928 889 +4 1350 874 836 860 +4 1188 915 1187 860 +4 1188 860 1350 900 +4 1334 1274 1273 1362 +4 1350 860 922 826 +4 1222 1224 1242 1189 +4 1225 1272 1224 1189 +4 1222 986 937 972 +4 1225 1189 1222 1252 +4 1368 1222 1252 986 +4 1368 1367 1190 1219 +4 1288 944 992 1006 +4 1188 1189 1225 1252 +4 1188 1352 1190 1187 +4 1352 870 829 926 +4 1190 1187 1352 656 +4 625 1261 656 584 +4 1281 1221 1353 627 +4 1352 829 852 926 +4 1352 879 625 852 +4 1352 879 852 829 +4 1190 1220 1187 656 +4 1304 1190 1220 1219 +4 1186 1187 641 903 +4 1304 1305 620 624 +4 1220 1219 1367 1221 +4 1300 589 1281 1186 +4 656 1304 577 624 +4 1188 1367 1350 860 +4 1187 842 915 903 +4 1190 1189 1219 1305 +4 1188 1352 1187 926 +4 1300 589 613 627 +4 1300 1220 1218 1347 +4 1300 613 1221 627 +4 1186 910 922 842 +4 1186 922 860 842 +4 1360 833 1380 874 +4 1360 1270 1284 1330 +4 1334 1274 995 1273 +4 1334 1358 1200 760 +4 1334 1200 1273 760 +4 1334 1265 1354 1267 +4 1334 1354 1274 1267 +4 1334 1358 1267 1362 +4 862 1342 1344 823 +4 1342 823 1339 1344 +4 1344 1339 1355 1274 +4 1344 1339 1342 1355 +4 1212 704 1214 1213 +4 1201 734 688 713 +4 1365 1296 1202 1290 +4 1201 688 767 763 +4 1201 1202 713 763 +4 1201 713 688 763 +4 1296 949 1012 1035 +4 1326 1320 1340 869 +4 1295 1273 1211 940 +4 1295 1365 1200 1366 +4 1259 1365 1297 1260 +4 1296 1290 1343 1291 +4 1296 1202 1290 1291 +4 1295 1297 1365 1260 +4 1296 1034 1035 932 +4 1296 1035 1012 932 +4 1208 1297 1014 1336 +4 1333 894 1234 822 +4 1297 1336 1257 1027 +4 1234 1314 1205 1263 +4 1234 853 894 837 +4 1234 1336 837 894 +4 1207 390 907 406 +4 1207 907 1234 837 +4 1207 907 837 886 +4 1207 406 391 384 +4 1207 998 1208 391 +4 1207 998 391 886 +4 1207 406 907 886 +4 1207 391 406 886 +4 1316 1208 1207 1335 +4 1342 1339 1338 1355 +4 1259 1215 1365 1260 +4 1316 1207 1314 1335 +4 1316 1297 1259 1296 +4 1316 1297 1208 1335 +4 1234 1314 1335 1205 +4 1314 397 395 382 +4 1342 1344 1317 862 +4 1206 1203 1264 1205 +4 1264 1214 388 385 +4 1264 388 398 385 +4 1264 397 398 388 +4 386 1314 1264 397 +4 1264 397 388 386 +4 1203 1341 1364 1245 +4 1264 661 388 606 +4 386 1314 1206 1264 +4 1264 1214 606 388 +4 1203 1264 1245 1209 +4 1204 897 924 822 +4 1361 1205 1333 1335 +4 1335 1336 1361 1297 +4 1203 1245 1364 1209 +4 1326 1204 1209 849 +4 1204 924 917 822 +4 1245 1264 1215 1214 +4 1342 1317 890 862 +4 1206 1203 1209 1264 +4 1203 1260 1215 1205 +4 1244 688 1212 1201 +4 606 1245 651 657 +4 1245 574 651 657 +4 590 1245 1209 679 +4 1245 651 574 679 +4 1212 767 1201 688 +4 1212 767 688 790 +4 1212 704 1213 767 +4 1212 790 704 767 +4 1212 1201 1213 1215 +4 1212 1213 1201 767 +4 1285 1319 642 619 +4 1285 642 583 619 +4 695 1285 1286 762 +4 1285 762 1319 619 +4 1285 1286 762 619 +4 1285 1341 1371 1366 +4 1365 1244 1200 1366 +4 1326 917 1204 849 +4 1285 583 1286 619 +4 1244 1341 1285 1366 +4 1365 1201 1200 1244 +4 1244 1286 695 1366 +4 1244 1260 1341 1366 +4 1200 735 1358 1366 +4 1200 735 1366 734 +4 1200 735 734 696 +4 1200 1273 760 696 +4 1200 760 735 696 +4 1295 1257 1362 941 +4 1200 745 1273 696 +4 1200 713 745 696 +4 1273 1295 1211 1200 +4 1365 1200 1201 1202 +4 1361 1203 1260 1340 +4 1338 892 830 869 +4 1338 867 1340 869 +4 1338 830 867 869 +4 1342 880 845 890 +4 1338 1362 1339 1340 +4 1320 1340 1338 1339 +4 1333 1340 1338 867 +4 1326 1209 1364 849 +4 1333 1234 1204 822 +4 1333 822 867 848 +4 1333 848 1336 894 +4 1333 848 894 822 +4 1361 1205 1335 1297 +4 1333 1257 1336 848 +4 1364 849 1209 601 +4 1364 1271 601 582 +4 1364 601 678 582 +4 1364 1209 679 601 +4 1364 679 678 601 +4 574 1364 1245 679 +4 1364 1209 1245 679 +4 1326 867 828 869 +4 1326 1203 1333 1340 +4 1203 1340 1341 1260 +4 1326 828 1320 869 +4 980 1295 983 940 +4 1361 1203 1333 1205 +4 1203 1204 1333 1205 +4 1344 1320 1339 1293 +4 1320 1371 1293 1292 +4 1320 1363 1371 1292 +4 1363 1371 1293 576 +4 1363 1285 1371 576 +4 1363 1341 1271 1371 +4 1363 621 671 582 +4 1363 576 671 621 +4 1326 867 917 828 +4 1320 1339 823 914 +4 1320 823 925 914 +4 1326 828 917 876 +4 1320 1344 1339 914 +4 1320 1292 1344 914 +4 1320 1292 914 850 +4 1320 914 925 850 +4 604 1320 648 850 +4 1320 925 828 850 +4 604 1320 1292 1363 +4 1317 834 890 862 +4 1033 1354 950 974 +4 1342 892 823 890 +4 1370 1017 1033 950 +4 1370 1010 880 1017 +4 1370 950 1010 1017 +4 1332 1031 973 936 +4 1326 1271 828 876 +4 1332 968 1370 1294 +4 1342 892 890 845 +4 1334 1366 1358 1362 +4 1197 1349 1344 1337 +4 1198 1301 789 691 +4 1258 1033 936 974 +4 1317 875 865 834 +4 1326 1271 1320 828 +4 1274 1023 974 934 +4 1274 1362 1355 941 +4 1274 941 1355 980 +4 1274 1362 941 980 +4 1274 980 1355 1023 +4 1274 980 1023 934 +4 980 1273 1274 1362 +4 1274 934 995 980 +4 1274 1355 1354 1023 +4 1262 1323 1325 1199 +4 1198 691 728 742 +4 1198 728 691 789 +4 1325 1322 1262 1308 +4 1198 1265 1240 700 +4 1196 1262 1198 742 +4 1266 1319 1293 1358 +4 1313 1318 632 587 +4 1313 632 618 587 +4 1326 1340 1320 1271 +4 1318 1337 644 1313 +4 1318 1337 1293 644 +4 1313 615 1337 644 +4 1313 587 615 644 +4 1313 1318 587 644 +4 1195 1301 1313 1199 +4 1195 1199 1313 1337 +4 615 1195 578 628 +4 1195 578 628 612 +4 1195 1199 1325 1301 +4 1229 1230 1289 1272 +4 1229 861 921 840 +4 1289 909 1193 659 +4 1317 1375 1370 1294 +4 1321 921 825 923 +4 1321 923 825 862 +4 1193 1194 1321 1349 +4 1229 821 899 861 +4 1193 674 594 659 +4 1193 921 909 840 +4 1193 921 858 909 +4 1289 1195 1325 612 +4 1289 1193 594 659 +4 1289 594 649 659 +4 1289 1230 901 649 +4 1289 667 1230 649 +4 1289 594 667 649 +4 575 1230 1324 1289 +4 575 1289 1325 612 +4 1289 667 594 612 +4 1289 594 1193 612 +4 1229 1193 1349 1325 +4 1229 1272 1289 1325 +4 1298 1375 1229 1294 +4 1229 1193 1289 840 +4 1229 1321 1193 921 +4 1209 1326 1364 1203 +4 1196 1240 1262 742 +4 1229 1349 1193 1321 +4 1298 1247 1294 1272 +4 1261 1305 620 1324 +4 1295 1027 983 932 +4 1261 620 1230 1324 +4 1261 620 1305 624 +4 1261 620 624 584 +4 1261 1230 620 603 +4 1261 620 584 603 +4 1225 868 847 895 +4 1188 905 824 900 +4 1228 866 829 870 +4 1228 918 821 913 +4 1228 913 1230 851 +4 1228 918 913 851 +4 1228 821 918 866 +4 1228 866 918 829 +4 1228 1230 1352 829 +4 1228 1230 829 851 +4 1228 829 918 851 +4 1228 1305 1272 1189 +4 1295 1297 1027 932 +4 1322 1242 1239 1303 +4 1239 620 1324 575 +4 1239 620 575 645 +4 1239 575 1323 652 +4 1239 575 652 645 +4 1239 575 1324 1323 +4 1253 1308 1322 1224 +4 1322 1324 1224 1308 +4 1322 1224 1324 1242 +4 1322 1305 1239 1242 +4 1322 1239 1305 1324 +4 1322 1305 1242 1324 +4 1322 1323 1239 1324 +4 1253 726 687 765 +4 1241 741 1227 1253 +4 1241 741 1309 1227 +4 1253 702 726 765 +4 1253 1224 1322 1242 +4 1253 1243 1224 1242 +4 1253 1242 1322 726 +4 715 1253 765 702 +4 1258 946 1247 1248 +4 1033 1258 1332 1370 +4 1225 1223 1294 899 +4 1225 866 1189 870 +4 1223 971 1294 927 +4 1223 927 1294 847 +4 1223 951 1294 971 +4 1223 951 971 1008 +4 1223 1008 971 947 +4 1247 1224 1248 933 +4 1332 1298 1294 1375 +4 1332 1294 1298 1247 +4 1298 1229 1349 1325 +4 1196 1375 1258 1354 +4 1247 1308 1248 1224 +4 1298 1308 1247 1272 +4 1298 1325 1308 1272 +4 1317 1354 1375 1344 +4 1342 1370 1354 950 +4 1342 1354 1317 1344 +4 1355 1354 1342 1344 +4 1317 1321 1344 1349 +4 1317 1344 1375 1349 +4 1317 1344 1321 862 +4 1258 1370 1354 1375 +4 1258 936 987 974 +4 1258 1354 974 945 +4 1258 987 1240 945 +4 1258 974 987 945 +4 1258 946 1240 987 +4 1196 1247 1258 1375 +4 1197 1375 1354 1344 +4 1262 1322 1253 1308 +4 1262 1248 1247 1308 +4 1196 1197 1354 1240 +4 1325 1322 1323 1262 +4 1262 1199 1301 1323 +4 1262 1323 1301 727 +4 1262 701 727 742 +4 1262 727 691 742 +4 1262 727 1322 1323 +4 1369 797 1278 1237 +4 1369 797 1237 800 +4 1369 797 800 818 +4 1359 633 1279 596 +4 1359 1369 1279 1278 +4 1369 1250 797 818 +4 1249 817 802 796 +4 1249 1233 1210 796 +4 1249 808 1233 796 +4 1249 1369 802 1250 +4 1249 802 1369 818 +4 1249 802 818 808 +4 1249 796 802 808 +4 1376 873 820 855 +4 1350 922 1251 826 +4 1357 827 919 854 +4 1357 827 873 855 +4 1357 1210 1249 1238 +4 1359 596 1311 573 +4 1226 856 1357 1210 +4 1357 919 827 855 +4 1254 1310 1256 1235 +4 1310 1348 1235 1238 +4 1226 1238 1345 1348 +4 1251 922 920 826 +4 1310 795 1231 811 +4 1235 1369 1238 1237 +4 1254 794 818 809 +4 1235 1369 1249 1238 +4 1235 1249 1369 794 +4 1310 819 1256 795 +4 1235 1255 1192 1232 +4 1231 172 811 803 +4 1231 1315 1232 938 +4 1231 1232 1315 693 +4 1231 164 723 793 +4 1231 164 793 803 +4 1231 793 723 160 +4 1231 793 1037 803 +4 720 1191 1256 693 +4 1327 598 626 580 +4 1191 1256 1255 698 +4 1191 1192 721 709 +4 1191 693 785 721 +4 1191 721 785 698 +4 1254 1369 1237 800 +4 818 1254 809 800 +4 1254 798 1331 1255 +4 1254 1237 1235 1236 +4 1254 1236 1235 1255 +4 1295 1027 1297 1257 +4 1254 1369 1235 1237 +4 1236 1254 1237 1331 +4 1327 1192 1191 709 +4 1277 686 709 778 +4 1327 709 698 749 +4 1327 792 626 749 +4 1327 1351 709 749 +4 598 1327 626 749 +4 1277 1236 1307 1351 +4 1306 1356 638 593 +4 1306 1307 666 1351 +4 1307 665 573 666 +4 1277 1330 1379 1346 +4 1277 1330 1346 1192 +4 1345 1284 1329 1330 +4 1306 593 1377 1356 +4 1277 1379 1307 1236 +4 1328 1275 1356 694 +4 1306 579 675 616 +4 1306 593 666 616 +4 1306 616 675 593 +4 1328 1330 1372 1353 +4 1306 1307 1277 1379 +4 1306 646 1307 1379 +4 1306 646 1379 616 +4 1328 1377 1306 1353 +4 1306 1379 1353 616 +4 1276 710 1269 955 +4 1276 1315 710 955 +4 1312 733 690 757 +4 1276 1192 1277 686 +4 1275 1269 761 697 +4 1276 740 1192 686 +4 1276 761 740 686 +4 1276 740 761 710 +4 1276 1269 710 761 +4 1276 1315 1192 740 +4 1329 1270 1284 984 +4 1329 1284 931 984 +4 1345 985 931 965 +4 1329 1284 1270 1330 +4 1345 1235 1192 1232 +4 1345 1348 1235 1232 +4 1345 985 1348 1315 +4 1345 1329 1276 1192 +4 1345 1276 1315 1192 +4 1345 1348 1232 1315 +4 1345 1232 1192 1315 +4 1359 633 596 585 +4 1226 1238 1357 1346 +4 1226 1357 1238 1210 +4 1226 1238 1348 1210 +4 1226 1345 1346 1284 +4 1311 1282 1379 646 +4 1251 1379 1353 1330 +4 1295 1297 1361 1257 +4 1283 891 881 833 +4 1283 820 873 891 +4 1283 1330 1284 1346 +4 1283 833 863 891 +4 1283 863 820 891 +4 1311 1379 1307 646 +4 1311 614 1282 646 +4 1376 1282 843 882 +4 1211 1200 1365 1202 +4 1376 843 904 882 +4 1376 904 843 855 +4 1211 940 958 1034 +4 1311 1346 1236 1379 +4 1311 1282 1376 1379 +4 1311 843 1376 1282 +4 1279 883 843 633 +4 1359 1278 1279 633 +4 1359 1238 1369 1237 +4 1211 940 989 958 +4 1311 1236 1307 1379 +4 1359 665 580 608 +4 665 1359 1307 573 +4 1279 1278 832 883 +4 1279 832 843 883 +4 1279 1376 1311 843 +4 1279 843 832 855 +4 1279 1238 1357 1250 +4 919 1279 1357 1250 +4 1279 1278 1250 832 +4 1281 617 1186 589 +4 1281 617 589 627 +4 1281 859 1186 617 +4 1360 1350 1251 826 +4 1353 1350 1281 1251 +4 1281 617 627 586 +4 1281 1282 643 586 +4 1281 643 617 586 +4 1372 1251 1353 1330 +4 1268 1004 1380 942 +4 1360 1251 863 826 +4 1350 1221 1281 1186 +4 1350 1221 1367 1378 +4 1360 863 874 826 +4 1350 874 860 826 +4 1350 1221 1186 1367 +4 1350 1367 1186 860 +4 1188 870 1190 1352 +4 1188 1189 870 1225 +4 836 1350 860 900 +4 1328 1356 1306 1377 +4 1328 1275 1277 1356 +4 1328 1277 1306 1356 +4 1328 1379 1277 1330 +4 1275 1270 1269 1217 +4 1275 1270 1329 1269 +4 1251 1372 1350 1378 +4 1275 1330 1329 1270 +4 1381 961 1216 1024 +4 1381 961 1024 1028 +4 1287 1367 1368 1219 +4 1287 1367 1373 1378 +4 1381 1217 1216 961 +4 1381 1217 961 1028 +4 1268 1381 979 1270 +4 1211 940 1273 989 +4 1381 1024 935 1028 +4 1381 935 979 1028 +4 1280 769 708 780 +4 1312 1218 690 780 +4 1347 775 1303 787 +4 1218 1347 1280 1221 +4 1347 605 655 669 +4 1304 1190 1219 1305 +4 1304 577 1347 1220 +4 1304 1219 1303 1242 +4 1347 680 605 669 +4 1218 708 787 729 +4 1218 780 708 729 +4 1312 1373 1218 1280 +4 1218 729 690 780 +4 1227 741 699 729 +4 1299 759 747 712 +4 1309 1021 969 1030 +4 1227 692 1303 1242 +4 1304 1303 1347 605 +4 1304 1303 1218 1347 +4 1304 1347 1218 1220 +4 1304 581 1239 1303 +4 1304 1303 1239 1305 +4 1304 581 1303 605 +4 1304 581 605 680 +4 1304 624 581 680 +4 1304 1303 1305 1242 +4 1288 1350 1188 1367 +4 1190 1189 1352 870 +4 1188 1350 1302 900 +4 1190 1367 1220 1219 +4 1287 1309 1219 1222 +4 1190 1367 1187 1220 +4 1309 730 1021 747 +4 1299 1219 1227 1218 +4 1309 730 699 741 +4 1299 690 1312 1373 +4 1227 1303 1218 1219 +4 1227 1303 1219 1242 +4 1299 1217 757 712 +4 1227 1219 1222 1242 +4 1299 1227 1309 699 +4 1287 1006 1381 975 +4 937 1368 1222 1287 +4 1287 1309 937 975 +4 1309 937 975 1030 +4 1309 1216 953 975 +4 1309 953 1030 975 +4 1309 1222 1227 1219 +4 1374 846 905 900 +4 1374 992 1288 944 +4 1374 992 976 184 +4 1374 184 976 872 +4 1287 1268 1288 1378 +4 1287 1288 1368 1367 +4 1368 1222 1219 1189 +4 1374 928 1288 992 +4 1368 1252 1222 1189 +4 1374 1288 1368 944 +4 1374 976 1252 872 +4 1374 905 846 872 +4 1300 1347 1218 1221 +4 1300 1280 1347 1221 +4 1300 1280 1221 613 +4 1300 1220 577 656 +4 1300 577 653 656 +4 1300 1220 1347 577 +4 1300 589 1186 653 +4 1300 589 653 613 +4 1300 653 577 613 +4 1295 1211 1296 1034 +4 1361 1340 1366 1362 +4 1361 1366 1340 1260 +4 1316 1290 382 396 +4 1259 1205 1314 1215 +4 1259 1205 1297 1335 +4 1259 1365 1215 1290 +4 1361 1336 1333 1257 +4 1361 1297 1336 1257 +4 1295 1362 1273 940 +4 1295 1296 1365 1297 +4 1366 1361 1362 1295 + +CELL_TYPES 7206 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 + +CELL_DATA 7206 +SCALARS CellEntityIds int 1 +LOOKUP_TABLE default +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 diff --git a/tests/data/gmsh_2d.vtk b/tests/data/gmsh_2d.vtk new file mode 100644 index 0000000000..adefc91ca6 --- /dev/null +++ b/tests/data/gmsh_2d.vtk @@ -0,0 +1,54446 @@ +# vtk DataFile Version 2.0 +model, Created by Gmsh 4.13.1 +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 7705 double +-0.16 -0.2 0 +-0.16 -0.1 0 +0.16 -0.2 0 +0.16 -0.1 0 +0 -0.1 0 +-0.16 0.1 0 +0 0.1 0 +0.16 0.1 0 +-0.16 0.2 0 +0.16 0.2 0 +-0.2 -0.1 0 +-0.2 0.1 0 +0.2 -0.1 0 +0.2 0.1 0 +-0.16 -0.105 0 +-0.16 -0.11 0 +-0.16 -0.115 0 +-0.16 -0.12 0 +-0.16 -0.1250000000000001 0 +-0.16 -0.1300000000000001 0 +-0.16 -0.1350000000000001 0 +-0.16 -0.1400000000000001 0 +-0.16 -0.1450000000000001 0 +-0.16 -0.1500000000000001 0 +-0.16 -0.1550000000000001 0 +-0.16 -0.1600000000000001 0 +-0.16 -0.1650000000000001 0 +-0.16 -0.1700000000000001 0 +-0.16 -0.1750000000000001 0 +-0.16 -0.1800000000000001 0 +-0.16 -0.1850000000000001 0 +-0.16 -0.19 0 +-0.16 -0.195 0 +0.155 -0.2 0 +0.15 -0.2 0 +0.145 -0.2 0 +0.14 -0.2 0 +0.135 -0.2 0 +0.13 -0.2 0 +0.125 -0.2 0 +0.1200000000000001 -0.2 0 +0.115 -0.2 0 +0.11 -0.2 0 +0.105 -0.2 0 +0.1 -0.2 0 +0.09500000000000003 -0.2 0 +0.09000000000000002 -0.2 0 +0.08500000000000005 -0.2 0 +0.08000000000000004 -0.2 0 +0.07500000000000004 -0.2 0 +0.07000000000000003 -0.2 0 +0.06500000000000003 -0.2 0 +0.06000000000000005 -0.2 0 +0.05500000000000005 -0.2 0 +0.05000000000000004 -0.2 0 +0.04500000000000004 -0.2 0 +0.04000000000000004 -0.2 0 +0.03500000000000003 -0.2 0 +0.03000000000000003 -0.2 0 +0.02500000000000002 -0.2 0 +0.02000000000000002 -0.2 0 +0.01500000000000001 -0.2 0 +0.01000000000000006 -0.2 0 +0.00500000000000006 -0.2 0 +5.551115123125783e-17 -0.2 0 +-0.004999999999999949 -0.2 0 +-0.009999999999999953 -0.2 0 +-0.01499999999999996 -0.2 0 +-0.01999999999999996 -0.2 0 +-0.02499999999999997 -0.2 0 +-0.02999999999999997 -0.2 0 +-0.03499999999999998 -0.2 0 +-0.03999999999999998 -0.2 0 +-0.04499999999999998 -0.2 0 +-0.04999999999999999 -0.2 0 +-0.05499999999999999 -0.2 0 +-0.06 -0.2 0 +-0.065 -0.2 0 +-0.07000000000000001 -0.2 0 +-0.07500000000000001 -0.2 0 +-0.08000000000000002 -0.2 0 +-0.08500000000000002 -0.2 0 +-0.09000000000000002 -0.2 0 +-0.09500000000000003 -0.2 0 +-0.1 -0.2 0 +-0.105 -0.2 0 +-0.11 -0.2 0 +-0.115 -0.2 0 +-0.1200000000000001 -0.2 0 +-0.1250000000000001 -0.2 0 +-0.1300000000000001 -0.2 0 +-0.135 -0.2 0 +-0.14 -0.2 0 +-0.145 -0.2 0 +-0.15 -0.2 0 +-0.155 -0.2 0 +0.16 -0.105 0 +0.16 -0.11 0 +0.16 -0.115 0 +0.16 -0.12 0 +0.16 -0.1250000000000001 0 +0.16 -0.1300000000000001 0 +0.16 -0.1350000000000001 0 +0.16 -0.1400000000000001 0 +0.16 -0.1450000000000001 0 +0.16 -0.1500000000000001 0 +0.16 -0.1550000000000001 0 +0.16 -0.1600000000000001 0 +0.16 -0.1650000000000001 0 +0.16 -0.1700000000000001 0 +0.16 -0.1750000000000001 0 +0.16 -0.1800000000000001 0 +0.16 -0.1850000000000001 0 +0.16 -0.19 0 +0.16 -0.195 0 +0.004999999999999997 -0.1 0 +0.009999999999999995 -0.1 0 +0.01499999999999999 -0.1 0 +0.01999999999999999 -0.1 0 +0.02499999999999999 -0.1 0 +0.03 -0.1 0 +0.035 -0.1 0 +0.03999999999999999 -0.1 0 +0.04499999999999999 -0.1 0 +0.04999999999999999 -0.1 0 +0.055 -0.1 0 +0.06 -0.1 0 +0.065 -0.1 0 +0.07000000000000001 -0.1 0 +0.075 -0.1 0 +0.08 -0.1 0 +0.08500000000000001 -0.1 0 +0.09000000000000001 -0.1 0 +0.09499999999999999 -0.1 0 +0.1 -0.1 0 +0.105 -0.1 0 +0.11 -0.1 0 +0.115 -0.1 0 +0.12 -0.1 0 +0.125 -0.1 0 +0.13 -0.1 0 +0.135 -0.1 0 +0.14 -0.1 0 +0.145 -0.1 0 +0.15 -0.1 0 +0.155 -0.1 0 +-0.155 -0.1 0 +-0.15 -0.1 0 +-0.145 -0.1 0 +-0.14 -0.1 0 +-0.135 -0.1 0 +-0.13 -0.1 0 +-0.125 -0.1 0 +-0.12 -0.1 0 +-0.115 -0.1 0 +-0.11 -0.1 0 +-0.105 -0.1 0 +-0.1 -0.1 0 +-0.09500000000000003 -0.1 0 +-0.09000000000000002 -0.1 0 +-0.08500000000000002 -0.1 0 +-0.08000000000000003 -0.1 0 +-0.07500000000000004 -0.1 0 +-0.07000000000000003 -0.1 0 +-0.06500000000000003 -0.1 0 +-0.06000000000000003 -0.1 0 +-0.05500000000000003 -0.1 0 +-0.05000000000000003 -0.1 0 +-0.04500000000000003 -0.1 0 +-0.04000000000000004 -0.1 0 +-0.03500000000000004 -0.1 0 +-0.03000000000000004 -0.1 0 +-0.02500000000000004 -0.1 0 +-0.02000000000000002 -0.1 0 +-0.01500000000000001 -0.1 0 +-0.01000000000000001 -0.1 0 +-0.005000000000000004 -0.1 0 +-0.16 0.095 0 +-0.16 0.09 0 +-0.16 0.08500000000000002 0 +-0.16 0.08000000000000002 0 +-0.16 0.07500000000000001 0 +-0.16 0.07000000000000003 0 +-0.16 0.06500000000000003 0 +-0.16 0.06000000000000003 0 +-0.16 0.05500000000000002 0 +-0.16 0.05000000000000002 0 +-0.16 0.04499999999999998 0 +-0.16 0.03999999999999998 0 +-0.16 0.03499999999999998 0 +-0.16 0.02999999999999997 0 +-0.16 0.02499999999999995 0 +-0.16 0.01999999999999996 0 +-0.16 0.01499999999999997 0 +-0.16 0.009999999999999953 0 +-0.16 0.004999999999999977 0 +-0.16 -4.163336342344337e-17 0 +-0.16 -0.005000000000000046 0 +-0.16 -0.01000000000000005 0 +-0.16 -0.01500000000000004 0 +-0.16 -0.02000000000000003 0 +-0.16 -0.02500000000000002 0 +-0.16 -0.03000000000000003 0 +-0.16 -0.03500000000000002 0 +-0.16 -0.04000000000000003 0 +-0.16 -0.04500000000000003 0 +-0.16 -0.05000000000000003 0 +-0.16 -0.05500000000000003 0 +-0.16 -0.06000000000000003 0 +-0.16 -0.06500000000000002 0 +-0.16 -0.07000000000000001 0 +-0.16 -0.07500000000000001 0 +-0.16 -0.08000000000000002 0 +-0.16 -0.08500000000000002 0 +-0.16 -0.09000000000000002 0 +-0.16 -0.09500000000000001 0 +0 0.09500000000000001 0 +0 0.09000000000000001 0 +0 0.08500000000000003 0 +0 0.08000000000000003 0 +0 0.07500000000000002 0 +0 0.07000000000000003 0 +0 0.06500000000000003 0 +0 0.06000000000000004 0 +0 0.05500000000000003 0 +0 0.05000000000000003 0 +0 0.04500000000000001 0 +0 0.04000000000000001 0 +0 0.035 0 +0 0.03 0 +0 0.02499999999999999 0 +0 0.02 0 +0 0.01500000000000001 0 +0 0.01000000000000001 0 +0 0.005000000000000004 0 +0 6.938893903907228e-18 0 +0 -0.004999999999999991 0 +0 -0.009999999999999995 0 +0 -0.015 0 +0 -0.02 0 +0 -0.02499999999999999 0 +0 -0.03 0 +0 -0.035 0 +0 -0.03999999999999999 0 +0 -0.045 0 +0 -0.05 0 +0 -0.055 0 +0 -0.06 0 +0 -0.065 0 +0 -0.07000000000000001 0 +0 -0.07500000000000001 0 +0 -0.08 0 +0 -0.08500000000000001 0 +0 -0.09000000000000001 0 +0 -0.095 0 +-0.155 0.1 0 +-0.15 0.1 0 +-0.145 0.1 0 +-0.14 0.1 0 +-0.135 0.1 0 +-0.13 0.1 0 +-0.125 0.1 0 +-0.12 0.1 0 +-0.115 0.1 0 +-0.11 0.1 0 +-0.105 0.1 0 +-0.1 0.1 0 +-0.09500000000000003 0.1 0 +-0.09000000000000002 0.1 0 +-0.08500000000000002 0.1 0 +-0.08000000000000003 0.1 0 +-0.07500000000000004 0.1 0 +-0.07000000000000003 0.1 0 +-0.06500000000000003 0.1 0 +-0.06000000000000003 0.1 0 +-0.05500000000000003 0.1 0 +-0.05000000000000003 0.1 0 +-0.04500000000000003 0.1 0 +-0.04000000000000004 0.1 0 +-0.03500000000000004 0.1 0 +-0.03000000000000004 0.1 0 +-0.02500000000000004 0.1 0 +-0.02000000000000002 0.1 0 +-0.01500000000000001 0.1 0 +-0.01000000000000001 0.1 0 +-0.005000000000000004 0.1 0 +0.16 0.095 0 +0.16 0.09 0 +0.16 0.08500000000000002 0 +0.16 0.08000000000000002 0 +0.16 0.07500000000000001 0 +0.16 0.07000000000000003 0 +0.16 0.06500000000000003 0 +0.16 0.06000000000000003 0 +0.16 0.05500000000000002 0 +0.16 0.05000000000000002 0 +0.16 0.04499999999999998 0 +0.16 0.03999999999999998 0 +0.16 0.03499999999999998 0 +0.16 0.02999999999999997 0 +0.16 0.02499999999999995 0 +0.16 0.01999999999999996 0 +0.16 0.01499999999999997 0 +0.16 0.009999999999999953 0 +0.16 0.004999999999999977 0 +0.16 -4.163336342344337e-17 0 +0.16 -0.005000000000000046 0 +0.16 -0.01000000000000005 0 +0.16 -0.01500000000000004 0 +0.16 -0.02000000000000003 0 +0.16 -0.02500000000000002 0 +0.16 -0.03000000000000003 0 +0.16 -0.03500000000000002 0 +0.16 -0.04000000000000003 0 +0.16 -0.04500000000000003 0 +0.16 -0.05000000000000003 0 +0.16 -0.05500000000000003 0 +0.16 -0.06000000000000003 0 +0.16 -0.06500000000000002 0 +0.16 -0.07000000000000001 0 +0.16 -0.07500000000000001 0 +0.16 -0.08000000000000002 0 +0.16 -0.08500000000000002 0 +0.16 -0.09000000000000002 0 +0.16 -0.09500000000000001 0 +0.004999999999999997 0.1 0 +0.009999999999999995 0.1 0 +0.01499999999999999 0.1 0 +0.01999999999999999 0.1 0 +0.02499999999999999 0.1 0 +0.03 0.1 0 +0.035 0.1 0 +0.03999999999999999 0.1 0 +0.04499999999999999 0.1 0 +0.04999999999999999 0.1 0 +0.055 0.1 0 +0.06 0.1 0 +0.065 0.1 0 +0.07000000000000001 0.1 0 +0.075 0.1 0 +0.08 0.1 0 +0.08500000000000001 0.1 0 +0.09000000000000001 0.1 0 +0.09499999999999999 0.1 0 +0.1 0.1 0 +0.105 0.1 0 +0.11 0.1 0 +0.115 0.1 0 +0.12 0.1 0 +0.125 0.1 0 +0.13 0.1 0 +0.135 0.1 0 +0.14 0.1 0 +0.145 0.1 0 +0.15 0.1 0 +0.155 0.1 0 +-0.16 0.195 0 +-0.16 0.19 0 +-0.16 0.185 0 +-0.16 0.18 0 +-0.16 0.175 0 +-0.16 0.17 0 +-0.16 0.165 0 +-0.16 0.16 0 +-0.16 0.155 0 +-0.16 0.15 0 +-0.16 0.145 0 +-0.16 0.14 0 +-0.16 0.135 0 +-0.16 0.1299999999999999 0 +-0.16 0.1249999999999999 0 +-0.16 0.1199999999999999 0 +-0.16 0.1149999999999999 0 +-0.16 0.11 0 +-0.16 0.105 0 +0.16 0.195 0 +0.16 0.19 0 +0.16 0.185 0 +0.16 0.18 0 +0.16 0.175 0 +0.16 0.17 0 +0.16 0.165 0 +0.16 0.16 0 +0.16 0.155 0 +0.16 0.15 0 +0.16 0.145 0 +0.16 0.14 0 +0.16 0.135 0 +0.16 0.1299999999999999 0 +0.16 0.1249999999999999 0 +0.16 0.1199999999999999 0 +0.16 0.1149999999999999 0 +0.16 0.11 0 +0.16 0.105 0 +-0.155 0.2 0 +-0.15 0.2 0 +-0.145 0.2 0 +-0.14 0.2 0 +-0.135 0.2 0 +-0.13 0.2 0 +-0.125 0.2 0 +-0.1200000000000001 0.2 0 +-0.115 0.2 0 +-0.11 0.2 0 +-0.105 0.2 0 +-0.1 0.2 0 +-0.09500000000000003 0.2 0 +-0.09000000000000002 0.2 0 +-0.08500000000000005 0.2 0 +-0.08000000000000004 0.2 0 +-0.07500000000000004 0.2 0 +-0.07000000000000003 0.2 0 +-0.06500000000000003 0.2 0 +-0.06000000000000005 0.2 0 +-0.05500000000000005 0.2 0 +-0.05000000000000004 0.2 0 +-0.04500000000000004 0.2 0 +-0.04000000000000004 0.2 0 +-0.03500000000000003 0.2 0 +-0.03000000000000003 0.2 0 +-0.02500000000000002 0.2 0 +-0.02000000000000002 0.2 0 +-0.01500000000000001 0.2 0 +-0.01000000000000006 0.2 0 +-0.00500000000000006 0.2 0 +-5.551115123125783e-17 0.2 0 +0.004999999999999949 0.2 0 +0.009999999999999953 0.2 0 +0.01499999999999996 0.2 0 +0.01999999999999996 0.2 0 +0.02499999999999997 0.2 0 +0.02999999999999997 0.2 0 +0.03499999999999998 0.2 0 +0.03999999999999998 0.2 0 +0.04499999999999998 0.2 0 +0.04999999999999999 0.2 0 +0.05499999999999999 0.2 0 +0.06 0.2 0 +0.065 0.2 0 +0.07000000000000001 0.2 0 +0.07500000000000001 0.2 0 +0.08000000000000002 0.2 0 +0.08500000000000002 0.2 0 +0.09000000000000002 0.2 0 +0.09500000000000003 0.2 0 +0.1 0.2 0 +0.105 0.2 0 +0.11 0.2 0 +0.115 0.2 0 +0.1200000000000001 0.2 0 +0.1250000000000001 0.2 0 +0.1300000000000001 0.2 0 +0.135 0.2 0 +0.14 0.2 0 +0.145 0.2 0 +0.15 0.2 0 +0.155 0.2 0 +-0.2 0.09500000000000001 0 +-0.2 0.09000000000000001 0 +-0.2 0.08500000000000003 0 +-0.2 0.08000000000000003 0 +-0.2 0.07500000000000002 0 +-0.2 0.07000000000000003 0 +-0.2 0.06500000000000003 0 +-0.2 0.06000000000000004 0 +-0.2 0.05500000000000003 0 +-0.2 0.05000000000000003 0 +-0.2 0.04500000000000001 0 +-0.2 0.04000000000000001 0 +-0.2 0.035 0 +-0.2 0.03 0 +-0.2 0.02499999999999999 0 +-0.2 0.02 0 +-0.2 0.01500000000000001 0 +-0.2 0.01000000000000001 0 +-0.2 0.005000000000000004 0 +-0.2 6.938893903907228e-18 0 +-0.2 -0.004999999999999991 0 +-0.2 -0.009999999999999995 0 +-0.2 -0.015 0 +-0.2 -0.02 0 +-0.2 -0.02499999999999999 0 +-0.2 -0.03 0 +-0.2 -0.035 0 +-0.2 -0.03999999999999999 0 +-0.2 -0.045 0 +-0.2 -0.05 0 +-0.2 -0.055 0 +-0.2 -0.06 0 +-0.2 -0.065 0 +-0.2 -0.07000000000000001 0 +-0.2 -0.07500000000000001 0 +-0.2 -0.08 0 +-0.2 -0.08500000000000001 0 +-0.2 -0.09000000000000001 0 +-0.2 -0.095 0 +-0.195 -0.1 0 +-0.19 -0.1 0 +-0.185 -0.1 0 +-0.18 -0.1 0 +-0.175 -0.1 0 +-0.17 -0.1 0 +-0.165 -0.1 0 +-0.195 0.1 0 +-0.19 0.1 0 +-0.185 0.1 0 +-0.18 0.1 0 +-0.175 0.1 0 +-0.17 0.1 0 +-0.165 0.1 0 +0.165 -0.1 0 +0.17 -0.1 0 +0.175 -0.1 0 +0.18 -0.1 0 +0.185 -0.1 0 +0.19 -0.1 0 +0.195 -0.1 0 +0.2 0.09500000000000001 0 +0.2 0.09000000000000001 0 +0.2 0.08500000000000003 0 +0.2 0.08000000000000003 0 +0.2 0.07500000000000002 0 +0.2 0.07000000000000003 0 +0.2 0.06500000000000003 0 +0.2 0.06000000000000004 0 +0.2 0.05500000000000003 0 +0.2 0.05000000000000003 0 +0.2 0.04500000000000001 0 +0.2 0.04000000000000001 0 +0.2 0.035 0 +0.2 0.03 0 +0.2 0.02499999999999999 0 +0.2 0.02 0 +0.2 0.01500000000000001 0 +0.2 0.01000000000000001 0 +0.2 0.005000000000000004 0 +0.2 6.938893903907228e-18 0 +0.2 -0.004999999999999991 0 +0.2 -0.009999999999999995 0 +0.2 -0.015 0 +0.2 -0.02 0 +0.2 -0.02499999999999999 0 +0.2 -0.03 0 +0.2 -0.035 0 +0.2 -0.03999999999999999 0 +0.2 -0.045 0 +0.2 -0.05 0 +0.2 -0.055 0 +0.2 -0.06 0 +0.2 -0.065 0 +0.2 -0.07000000000000001 0 +0.2 -0.07500000000000001 0 +0.2 -0.08 0 +0.2 -0.08500000000000001 0 +0.2 -0.09000000000000001 0 +0.2 -0.095 0 +0.165 0.1 0 +0.17 0.1 0 +0.175 0.1 0 +0.18 0.1 0 +0.185 0.1 0 +0.19 0.1 0 +0.195 0.1 0 +0.01245903922207366 -0.1497831906009124 0 +0.08750000000000005 -0.15 0 +-0.04249999999999964 -0.15 0 +-0.1036890445944196 -0.150027180587496 0 +0.04978344847704108 -0.1391486578106036 0 +0.1228582506795479 -0.1630300668122953 0 +-0.07249999999999983 -0.1660624999999999 0 +-0.07181953320795192 -0.1326984963219894 0 +-0.01555616304972682 -0.1669446320749784 0 +-0.0149999999999998 -0.1325624999999999 0 +0.1138804959602991 -0.1319467727781645 0 +-0.1278953386760795 -0.168462912617002 0 +-0.1281006211053498 -0.1316582353587396 0 +0.06178298922800717 -0.168418144075404 0 +0.03268243450380377 -0.1707822357654411 0 +0.02614369100904311 -0.1268271362950847 0 +0.07391151685393263 -0.1268346207865169 0 +0.09909548651655709 -0.1738672993962214 0 +-0.09745820839686277 -0.17470621149156 0 +-0.04847030995571065 -0.1744153172934353 0 +-0.04832201052295326 -0.125310801578443 0 +-0.09652461548827099 -0.125212409976934 0 +0.008426013913963777 -0.1753302556322738 0 +0.1358546770561736 -0.1429934499115435 0 +0.004486035799224093 -0.1221076059611355 0 +0.1378786300879981 -0.1784395289585382 0 +0.09433762704191206 -0.1224603249356011 0 +0.1323432316117459 -0.1212224592090158 0 +-0.1388563283336758 -0.15 0 +0.07937528792192364 -0.1795477305927699 0 +0.03311556979731765 -0.1510686033869138 0 +0.06741880788507004 -0.149520463677376 0 +0.04502613281655362 -0.121775312848308 0 +0.1075678574190498 -0.1503425863511673 0 +-0.02990545803023772 -0.1802449670081765 0 +-0.02916872987350232 -0.1199718297315023 0 +-0.06175779998109401 -0.1493706031816844 0 +-0.0829325829800036 -0.1497380498748846 0 +-0.006778480113636325 -0.15 0 +0.1166235753436601 -0.1808834218581284 0 +-0.114408744302079 -0.1822363461786654 0 +-0.1144357299740426 -0.1188784148237662 0 +0.04798694873313185 -0.1817331113070895 0 +-0.1415119781483638 -0.1819172142976778 0 +-0.1425259889647839 -0.1176002469694207 0 +0.1422253787094186 -0.1589213879790212 0 +-0.120678164166838 -0.1517705033563109 0 +-0.02463924005681796 -0.1522358310931902 0 +-0.06488360183026635 -0.1818200378793189 0 +-0.0802728735780439 -0.1178723915916527 0 +0.04912533213759379 -0.156344603669228 0 +-0.06396938686847728 -0.1177899343797091 0 +-0.006835534043342444 -0.1829081561069342 0 +-0.03162080373784851 -0.1365409117961375 0 +-0.1126869642902981 -0.1354016906761482 0 +-0.08124831807446223 -0.1839227367701933 0 +-0.1101951180930291 -0.1655398115101347 0 +0.06105906695035297 -0.116510594641608 0 +-0.011187414892903 -0.1164449732162141 0 +0.07790662353634917 -0.1627745006248145 0 +-0.03528411921934278 -0.1648140568004312 0 +0.02243117761598494 -0.1839078803873218 0 +0.1096439285356464 -0.1159980087738478 0 +0.09801571560596914 -0.1383493551427437 0 +-0.144042752891114 -0.1351374802630838 0 +-0.1437987767958102 -0.1650139744925625 0 +0.06394552411508711 -0.1838526873007356 0 +0.003158610680978095 -0.1375930515763161 0 +0.01916230635456844 -0.1641483942293258 0 +0.1452026777452856 -0.1296992313211482 0 +0.002484159110771771 -0.1625729879526189 0 +0.1211314792464127 -0.1450330552146291 0 +0.01746587870274155 -0.1144643362145615 0 +0.08199732849215419 -0.1145611877230635 0 +0.1458707525069807 -0.1152420905874859 0 +-0.05254173569307664 -0.1605924655287429 0 +-0.09275567508806534 -0.1606676388787862 0 +-0.09402100189816422 -0.1385779897400497 0 +-0.058403160831855 -0.1353439215430768 0 +-0.1277953183213943 -0.1858140583437376 0 +-0.1276886659138157 -0.113848860293352 0 +0.09154763561794363 -0.1859225530630137 0 +0.03178351028103302 -0.1139810492839542 0 +0.03641764296560283 -0.1362827729038862 0 +0.02277746937418764 -0.1406037801842916 0 +0.0839071054048314 -0.1365048431111595 0 +0.09709516260395681 -0.1601879600365343 0 +0.06346287466655512 -0.1356987917172191 0 +-0.04182742744987862 -0.1867574058548999 0 +-0.04184800737219221 -0.1136018895533782 0 +0.03594280428991203 -0.1855076306004034 0 +0.1093942426961053 -0.1660194668499573 0 +-0.1020037177755617 -0.1868905830760875 0 +-0.1023273087461626 -0.1131788619313413 0 +0.1046324836335607 -0.1867999856649827 0 +0.1282040335838155 -0.1865171432578221 0 +0.1268932505228134 -0.1331056438498873 0 +0.1224208314720775 -0.1125269688935814 0 +0.04646852617789671 -0.1685713947366502 0 +0.1472534864394245 -0.1873736866103137 0 +0.1469583223090886 -0.1484097375007895 0 +0.01387542986785145 -0.1310965524337115 0 +-0.01917523515150529 -0.1871612187953006 0 +-0.04504092259996423 -0.1374910333822095 0 +-0.08432353098261304 -0.1707016534041972 0 +-0.08470808519646972 -0.1296286302013126 0 +0.004573719940131308 -0.187039915990891 0 +-0.06008460481153236 -0.1708195637663721 0 +0.05468640808526431 -0.1271773351093576 0 +0.1309465984404593 -0.1535717370467818 0 +0.1477547166971063 -0.170716888414528 0 +-0.05429984504605026 -0.1878141527736459 0 +0.08713595022976416 -0.1703454718242393 0 +0.1269658359485395 -0.1731874724781888 0 +-0.003445337882766263 -0.1721387924248886 0 +-0.1289202503792987 -0.1434690071473079 0 +-0.05424752272815771 -0.1120040454496977 0 +-0.0004380142825664721 -0.1122663644175771 0 +-0.09062795316401487 -0.1116417864924396 0 +-0.07267319408445415 -0.1447678544056759 0 +-0.02134786419623089 -0.1109200457073276 0 +-0.01743470442104729 -0.1439459324086459 0 +0.0707746222863911 -0.1115656371906014 0 +0.09959964227102025 -0.1113679743784238 0 +0.03698808248684865 -0.1599763798499181 0 +-0.003668082137380492 -0.1284590743253235 0 +-0.1297399946555298 -0.1577172494850609 0 +-0.1486841761294249 -0.1554257550774222 0 +-0.09121434764789128 -0.1889367826815225 0 +0.05115055415557102 -0.1107860497034892 0 +0.05673845033677861 -0.1485127950461788 0 +-0.02573159406626835 -0.1702904303076256 0 +0.1210836693284366 -0.123332902341303 0 +-0.03749745506834383 -0.1272303882424731 0 +0.0739827669232367 -0.1897398460150999 0 +-0.07341217790310628 -0.1091367696012895 0 +0.1032958944357754 -0.1288765144692554 0 +0.08489742634580771 -0.1251737641513795 0 +0.073382122185945 -0.1407572094209871 0 +-0.1491269163007672 -0.1109247356881127 0 +-0.1491227890937407 -0.1890759985371292 0 +0.02265873755140689 -0.153827543889388 0 +-0.05170446472090217 -0.1446694169799178 0 +-0.07188031751269935 -0.1897204079472047 0 +-0.07121405280176885 -0.1553070101028786 0 +0.1356594514619686 -0.111965608278281 0 +-0.08160464765260547 -0.160244570163988 0 +-0.1487986966718353 -0.1447916404722202 0 +0.04330016691440261 -0.14746509331347 0 +0.06105297180008845 -0.1576070747474528 0 +-0.0141673140932654 -0.1574618221476243 0 +-0.1489675021296433 -0.1746872261302067 0 +-0.148848283059092 -0.1256386531369923 0 +-0.02013664034342796 -0.1234034477691193 0 +0.07196094940603483 -0.171927632303891 0 +0.07732417147786323 -0.1525623014845409 0 +0.05463987570410312 -0.1896666230183096 0 +-0.07320095576174435 -0.1773362252070604 0 +-0.1070995232198989 -0.1263534034277775 0 +-0.1182667833659843 -0.1715068118139735 0 +0.1329738789942846 -0.1658073822036376 0 +0.03774587026811116 -0.1268659896576993 0 +-0.1119942623828192 -0.1462056360631048 0 +-0.008678770417370113 -0.139852800256161 0 +0.1078600175162623 -0.1393552969297921 0 +-0.08123420017867009 -0.1396882963887667 0 +-0.03878815167869751 -0.1745036622913571 0 +0.1166805339465228 -0.1543983593437915 0 +0.01837226095669456 -0.173807419019672 0 +-0.1190586602714811 -0.128573103574073 0 +-0.01820870139048615 -0.1771202257709663 0 +-0.07216555464008342 -0.1227945099410104 0 +-0.1065828903348785 -0.1743359969857189 0 +0.09766622961326135 -0.1468550131998351 0 +-0.03246198596465488 -0.1901515286945169 0 +0.04125261949918096 -0.1100565297694673 0 +0.01444288837007806 -0.1898930816582146 0 +0.149910784238799 -0.1385442659571856 0 +-0.0326732561567676 -0.1097539959709156 0 +0.08702750859556778 -0.1600717632008566 0 +-0.03273013242953485 -0.1467461106364741 0 +-0.1186816373405668 -0.1905007311061608 0 +-0.06215300134206769 -0.1598941282850099 0 +0.1382668101952894 -0.1898216865087993 0 +-0.1190361901692362 -0.1094442050682572 0 +-0.1205692368988738 -0.1606128678302819 0 +-0.05828120464479709 -0.1256551643313704 0 +-0.1361543502369281 -0.1908152003592854 0 +-0.1019590118441788 -0.1338475980804579 0 +0.002498923195180862 -0.1467830386041376 0 +-0.1358849871912421 -0.1098172353651816 0 +-0.1372416673849549 -0.1727964364071973 0 +-0.1382339458055044 -0.1282358324011839 0 +0.1087256978752774 -0.1748934308547936 0 +-0.09269790116403057 -0.150763590410886 0 +0.05705335965299955 -0.1781011437339357 0 +0.04616090317405139 -0.1316961453021503 0 +0.1176870325311442 -0.1704049950329292 0 +0.1139715853799248 -0.1902854221285106 0 +0.008174971819199619 -0.1085597704117235 0 +-0.007105744076999387 -0.1629923148459748 0 +0.06427485495092419 -0.1256536280816901 0 +-0.100569030119241 -0.1658945922351348 0 +0.04456862616848764 -0.1914566868334948 0 +0.09032790662424232 -0.1096598987155875 0 +0.01365390921813106 -0.1405470719182056 0 +0.08324491670843634 -0.190552342923503 0 +-0.1210276277503619 -0.1377310713612853 0 +0.1506470946919212 -0.1566606630291817 0 +0.1512892275793452 -0.1228273393831684 0 +0.03932376643075201 -0.177542568172183 0 +-0.0449553435254227 -0.1654394069398645 0 +0.0285915796796317 -0.161766337871892 0 +-0.1123127543668398 -0.1557841040143708 0 +-0.02423220457975667 -0.1310347140775825 0 +0.135192703527992 -0.1296577351161664 0 +-0.03515141988096705 -0.1555849744760716 0 +-0.02270844220906105 -0.1613545017487791 0 +-0.06189020613031675 -0.1906966843625282 0 +0.05381415450266305 -0.1651833100057496 0 +0.02829262091708743 -0.1908838847813911 0 +-0.1250387778266896 -0.1766211541146531 0 +0.1516159203511138 -0.1791340225667286 0 +0.07007543428745196 -0.1581722935319751 0 +0.02496964051400562 -0.1086778587466358 0 +-0.01090631448067692 -0.1910336676461291 0 +-0.1264126640996927 -0.1224265162772792 0 +0.01034393015607772 -0.1669916438713701 0 +-0.08311541984650117 -0.1090464238828369 0 +-0.05649637443664247 -0.1791952990829003 0 +-0.1354386066353714 -0.1362493968607941 0 +0.09180179700041984 -0.1303002247762611 0 +0.03029056499994379 -0.1794866959481104 0 +-0.109941123784853 -0.1914464779634522 0 +-0.08835137543463194 -0.1211186817219829 0 +-0.110075924129217 -0.108586232467919 0 +-0.06250000000000004 -0.1084744619270179 0 +-0.02537795273516536 -0.1426812612270908 0 +0.1147844207142839 -0.1087586329829333 0 +0.1406164757456792 -0.1216807201984089 0 +0.01812761770312299 -0.1230006375328755 0 +0.0008746587303560254 -0.1795748185548031 0 +-0.08949581585052375 -0.1811107191426566 0 +0.15167609839329 -0.1080907864089812 0 +-0.08220469848849922 -0.1910496010250629 0 +0.08076745943203227 -0.1446528680475456 0 +0.1391389129829242 -0.1517113450584457 0 +-0.008028360042523133 -0.1080035385262153 0 +0.09092121661321598 -0.1424973306913561 0 +0.06265938435251228 -0.1079137126276251 0 +0.09843335182290293 -0.1923005845552269 0 +-0.06626077006904994 -0.1387677332580346 0 +-0.1353027378393544 -0.1641270590655814 0 +-0.002495566783313082 -0.1919193303672127 0 +0.01373210611085456 -0.1811984457140713 0 +0.01271386936345778 -0.1584652258733407 0 +-0.003786401129281422 -0.1206761429869799 0 +-0.1042362089078492 -0.1587223536688218 0 +0.08744222704433238 -0.1787198339566478 0 +0.02468486577266048 -0.1180193475040794 0 +-0.1519857000891149 -0.1627513168336582 0 +0.069912562217382 -0.1195581792235454 0 +-0.01135304197542632 -0.1253939066932682 0 +-0.1332299286251173 -0.179449344728741 0 +0.0529467312564383 -0.1191024488569446 0 +0.1056753796924842 -0.1587419557689307 0 +0.1395495376033342 -0.1700875859192831 0 +0.1103278927474784 -0.1241469828996305 0 +0.1031968270653219 -0.1196223693430568 0 +0.03060857474612657 -0.1427796169145107 0 +0.1221478076498474 -0.1921818435524437 0 +-0.1517823794482704 -0.1360029598626491 0 +-0.04372851117432723 -0.1581943113044291 0 +0.06260123975841124 -0.1922047968266693 0 +0.07096651200541043 -0.1800572982596181 0 +-0.06473635298225051 -0.130588884590776 0 +0.006119844854278744 -0.1307788514550884 0 +-0.05463735777806764 -0.1527706589450927 0 +0.02848582494607982 -0.1344514562785234 0 +-0.1333778697107806 -0.1194182592938977 0 +-0.1057040090067055 -0.1418876256721977 0 +0.09856222227722622 -0.1817765659100343 0 +-0.1400797865786162 -0.1580773430630548 0 +-0.04735612271681629 -0.1920303293944365 0 +0.1199823911564963 -0.1371177625958235 0 +0.1276428321823432 -0.1402707851136911 0 +0.0248464531520449 -0.1695364242089074 0 +-0.1408796644973237 -0.1423972583603383 0 +-0.151975923882663 -0.1816227675788464 0 +-0.1519757427378748 -0.1183796747856935 0 +0.1068994584013841 -0.1075759194791958 0 +-0.05105943722630078 -0.1325583240544654 0 +0.141976740248387 -0.1370370349073041 0 +-0.01046718834287219 -0.1754684874283024 0 +0.07798925066914346 -0.10777525553406 0 +0.101848493914684 -0.1663280106899871 0 +0.1133112570194522 -0.1455761651266499 0 +-0.05351925712776135 -0.1197726358005163 0 +-0.09187868241871601 -0.1685065890326127 0 +0.1421962706158796 -0.1074771834191143 0 +0.07944746317598222 -0.1712682545472137 0 +-0.04842133403879276 -0.1830988351144679 0 +-0.05300676797441203 -0.1684402119273772 0 +-0.04664887720906849 -0.1073478170540871 0 +-0.02503338527414248 -0.1924425453305349 0 +0.152299053867801 -0.1305432957181599 0 +0.06471684492766211 -0.1754979400494926 0 +-0.0005370449299440565 -0.1545234561049231 0 +0.1287304920764336 -0.1080242266382557 0 +-0.09228791289144403 -0.1314122557738673 0 +-0.09713450061691878 -0.107299157007309 0 +0.0940218514030349 -0.1669913670865701 0 +0.1526176148718509 -0.1927305943910271 0 +-0.04256799475130238 -0.1208394485501541 0 +0.009803074667805915 -0.1169830836231234 0 +0.05729969906843185 -0.1405049419535566 0 +-0.09766402234736914 -0.1928349825820303 0 +0.1523299708379008 -0.1644507243989792 0 +0.01708988127918137 -0.1068633215096026 0 +-0.09600250806428362 -0.1177986346516665 0 +0.06852331466322628 -0.1651835166508774 0 +0.0193903491368483 -0.1471072237426917 0 +-0.039560311266082 -0.1430206808266833 0 +0.003278241465883476 -0.1701652106948372 0 +0.02039271391931668 -0.132567202163044 0 +0.0890396519104338 -0.1170005546884395 0 +0.04201172818045133 -0.1547957591731176 0 +0.07875397708161605 -0.1212841496201567 0 +-0.107014609608463 -0.1189325712589112 0 +0.07702662580861579 -0.1335672584177746 0 +-0.06637327411419726 -0.1749239333049629 0 +0.0376220623193007 -0.1182679524767382 0 +0.123920775182692 -0.1518858471518697 0 +0.04268481470253015 -0.1401020776725205 0 +0.1240627016708377 -0.1803753127165923 0 +0.05030760084040101 -0.1743050291408717 0 +-0.07781650146394808 -0.1278129243891277 0 +-0.1275457898740259 -0.1928767029371883 0 +-0.03020700935512407 -0.1268388061773308 0 +-0.0871876174191856 -0.15554660355438 0 +-0.127543662166055 -0.1071596474597386 0 +-0.05880700582053618 -0.1429575712581169 0 +-0.08761592383947883 -0.1439695989391945 0 +0.1311598698864157 -0.1799728525710845 0 +0.1154271540785905 -0.1618423565656172 0 +0.03441472340934176 -0.1071092436062825 0 +-0.1279512026266297 -0.1504443088502417 0 +-0.0155610655089043 -0.1072136720779743 0 +0.006695379377851504 -0.1543192633052809 0 +-0.09718709100025261 -0.1450948137695521 0 +0.1529433941750487 -0.1156972433714012 0 +-0.1209745396403109 -0.1824270214047219 0 +-0.1073252620298907 -0.1818480653791704 0 +-0.1214779079429702 -0.1173806428422769 0 +0.1168195091765491 -0.1176336407302152 0 +-0.09700142366760986 -0.1819926677604062 0 +0.02076668263210684 -0.1930086739989372 0 +0.06964098216802124 -0.1323008819044188 0 +0.09349389794182525 -0.154111316213624 0 +-0.02055331175211145 -0.1370488398589623 0 +-0.1202834552415153 -0.1443953989530637 0 +0.09013569003702267 -0.1930142076514046 0 +-0.1432255271495153 -0.1930996882329104 0 +-0.03642387824838234 -0.1818823393126065 0 +-0.03897702112832532 -0.1929739560499182 0 +0.0445866500046737 -0.1617142389677872 0 +-0.03880933077621172 -0.1069918336726574 0 +0.03750000000000004 -0.1933645381155859 0 +0.1292762823221693 -0.114206291111653 0 +-0.1432872668516393 -0.1068765711147906 0 +0.1069948967263882 -0.1931621041600135 0 +0.01101499514450606 -0.1250593884648644 0 +0.06396244064872514 -0.1430784957158188 0 +0.03118886748659158 -0.1213287195305469 0 +-0.03001396961804868 -0.1599244534068233 0 +-0.04398520283875557 -0.1308042988857367 0 +-0.09721229410471693 -0.1554102360906962 0 +0.1312714107739925 -0.1930257242143598 0 +0.008356885626300508 -0.1932477240686001 0 +0.05397791615816609 -0.13409708816614 0 +0.1103055099409255 -0.1828388677070788 0 +-0.07603327617652121 -0.1510760497954108 0 +0.1531037845636899 -0.1448076507990385 0 +0.03748775667328254 -0.1435102260138302 0 +0.128180155974125 -0.1261871470655843 0 +-0.01340892693953644 -0.1828468101099788 0 +0.03951378150464367 -0.1675521141034172 0 +0.1444112649997984 -0.1810553384728404 0 +-0.03615380145506918 -0.117453589141733 0 +-0.07746079484509211 -0.1708057583352382 0 +-0.03153067746604669 -0.1737141023840574 0 +0.1444263376335413 -0.1941738651798881 0 +0.04979491037078283 -0.1495819316680922 0 +0.02616534213630811 -0.1479671863779462 0 +0.1336302916404135 -0.1731541477087968 0 +-0.01460775599957228 -0.1502324200219774 0 +-0.06542676220098079 -0.1238091915699841 0 +-0.02282035398526785 -0.182200540345177 0 +-0.1531896867874482 -0.1498981670855786 0 +0.1330146857329201 -0.1363854615426773 0 +-0.0263397549441694 -0.1064535877852054 0 +-0.03822760035036923 -0.1344923907353344 0 +0.1204713861334723 -0.1303550483623891 0 +0.04208033052998159 -0.1840679419198031 0 +0.1353076625015822 -0.1581152504798536 0 +0.0737712776101907 -0.1462111217350048 0 +0.1003422287726029 -0.1537368632744048 0 +0.1312958824346188 -0.1462336723989643 0 +-0.07186368825262203 -0.1823445831635187 0 +-0.01749611968719473 -0.193978153795709 0 +-0.08713690068418443 -0.1359611238691462 0 +-0.08169783818145479 -0.1763600900836012 0 +-0.04758302848916829 -0.1152397589324977 0 +-0.06611774199036367 -0.1656371781926817 0 +-0.002293429191303791 -0.1453289051229047 0 +-0.104407219138349 -0.1063375570616465 0 +0.1431724435178326 -0.144134898061734 0 +0.1064418026209675 -0.1328145701529923 0 +0.1534863472231698 -0.1515924415257082 0 +-0.1534646516866536 -0.1691708888620682 0 +0.05557938702992271 -0.1066625822190274 0 +0.04743002175894322 -0.106413545702969 0 +0.0846811638880865 -0.1072461523894147 0 +0.004037591827626475 -0.1060359214146124 0 +0.1534492150884093 -0.1850459746085641 0 +0.1524699323532077 -0.1731676194306621 0 +0.09201201211927493 -0.1755398404332216 0 +0.06933488656328517 -0.1934134734568284 0 +-0.01649838764741694 -0.1157450633614829 0 +0.1015885088644036 -0.1425745246444012 0 +-0.1451938266401401 -0.1491493360987272 0 +0.1219070719427644 -0.1062314330652611 0 +-0.08686898747907923 -0.1645214519257127 0 +0.08343551910993532 -0.183944503206886 0 +0.055662197973236 -0.1706148100844126 0 +0.05531001978439143 -0.1816590907842317 0 +0.02554640070008269 -0.1753450164291916 0 +-0.05674546333216364 -0.1933010035980566 0 +-0.04253600391661234 -0.1797638799883625 0 +0.05504681761079245 -0.1539575630796499 0 +0.1286811189249032 -0.159531378808115 0 +-0.06894996934110885 -0.1168290618394935 0 +0.008466266789841642 -0.1825737513412066 0 +0.1371714970363381 -0.1169609689205414 0 +-0.1353209323861354 -0.144437793332586 0 +-0.1532438896719926 -0.1060459250313246 0 +-0.1532372578189959 -0.1939501667514898 0 +0.03245539839723621 -0.1568608317941929 0 +0.09581859615769163 -0.1065224483661345 0 +0.1261762682515536 -0.1678172567674101 0 +0.08104083734757282 -0.1577836239758011 0 +-0.06874119173997226 -0.1493246630477141 0 +0.04962136729459839 -0.1250762182145215 0 +-0.104509141677902 -0.193800649873107 0 +-0.08321027970029234 -0.1220690867993879 0 +0.07799947738116517 -0.19365170453926 0 +0.1139518069658848 -0.1392214063865757 0 +-0.07501899896555772 -0.1599822045173538 0 +-0.1530941647164794 -0.1310027825395752 0 +0.07565554232627625 -0.1152191410693928 0 +0.1476560587541099 -0.1652317777242205 0 +-0.1439131399793619 -0.1278170206414108 0 +-0.1430698521234735 -0.1753051877629724 0 +-0.1122827112227772 -0.1740625376531808 0 +-0.04596968503525367 -0.1448244884657835 0 +0.1445938504591497 -0.1540264838868377 0 +0.05020694471297461 -0.1938598521671713 0 +-0.05658149342422504 -0.1061563851774727 0 +0.06103657340888425 -0.1307448396750542 0 +-0.06813396557331337 -0.1939914634516199 0 +0.0835983828002497 -0.1651519359826472 0 +-0.001300455803533572 -0.1856357782941879 0 +-0.008701399403912482 -0.1560430691956435 0 +-0.07424000792380225 -0.1383672171719924 0 +-0.04860039067609416 -0.1524975065030648 0 +0.1365826621241667 -0.1848912004320983 0 +-0.02715028808515726 -0.1135935987646818 0 +-0.05265743207587563 -0.1395646856459364 0 +-0.1118209195687196 -0.1289250957695106 0 +0.05873191429159609 -0.1223162545946804 0 +-0.08809412125949306 -0.1059899866086316 0 +-0.02788733662045954 -0.1867329427031807 0 +0.1202432795811566 -0.1860158630953866 0 +0.004520049802983306 -0.116634953351492 0 +-0.0767346253218622 -0.105941747953161 0 +0.0616319234487041 -0.1514980167553699 0 +-0.06754339535170711 -0.1066657442922998 0 +-0.1317134081970972 -0.1728795222323226 0 +-0.008641920177525242 -0.1322449836837509 0 +0.09587106747371638 -0.1148461952894993 0 +-0.001980863006366838 -0.1355544794847564 0 +-0.08937244280217094 -0.1737108260524755 0 +-0.01363267063727293 -0.1386536891264024 0 +-0.003409221848912531 -0.1057828008078615 0 +0.1253075747356807 -0.1201674165243297 0 +0.1106755065811071 -0.1556074227297594 0 +-0.1324812952164479 -0.1274209751432478 0 +0.1435494304213173 -0.1744573406084884 0 +-0.01012340475619787 -0.1449633787584748 0 +-0.05742548849487407 -0.1627965277496768 0 +0.08980329385753991 -0.1354419923448851 0 +-0.07825304320984817 -0.1323236149354172 0 +-0.001706039414379815 -0.1647526647332025 0 +-0.008849931474645788 -0.1679478917190418 0 +-0.07771421421937262 -0.1952118940104028 0 +0.06822001927885801 -0.1058883636436051 0 +-0.07885255371592645 -0.1449511897466472 0 +-0.05922473834427007 -0.1863858469720368 0 +-0.102233479467236 -0.1205925450543478 0 +-0.06492996496830505 -0.1549764116623943 0 +0.01808383584488427 -0.1372384977733661 0 +-0.1251272193783446 -0.1562666886819952 0 +-0.1280298679971481 -0.1629868391893901 0 +-0.08809516234492872 -0.1941926618541928 0 +0.005879926636686351 -0.1428812712170931 0 +-0.03921751006167647 -0.1601420058121496 0 +0.04598126899605873 -0.1139146469800495 0 +0.103935451907458 -0.1799298125651217 0 +-0.1018889962477245 -0.1765964825322218 0 +-0.06910778077637149 -0.1625507299006573 0 +0.03883844138631493 -0.1321147271499382 0 +-0.1277769411316556 -0.1377640414671588 0 +-0.1153061671451081 -0.1657628836935203 0 +0.09820221261139742 -0.1311075908620569 0 +-0.01875329391061328 -0.1710338480069744 0 +-0.0238069050168622 -0.1198936431650638 0 +0.0325381563918545 -0.1653587291475018 0 +-0.02541162168853898 -0.1761988946527463 0 +0.008208009841771037 -0.1353138476721832 0 +-0.1015916369375543 -0.1288020185535367 0 +-0.1549347419131192 -0.1571417215065681 0 +-0.1430227328986207 -0.1134802013400699 0 +-0.1433120411636286 -0.1870541368014198 0 +-0.005014445687544649 -0.1772352067098188 0 +0.02986041956677157 -0.1854612821556602 0 +0.03336933571114201 -0.1319528749667151 0 +-0.05827123529340605 -0.1133980921787043 0 +0.0157119956898198 -0.1690583329143621 0 +-0.01871959108190664 -0.1486644412452538 0 +-0.1079145039060185 -0.150337710475218 0 +-0.1194851982398694 -0.1774767949904328 0 +0.11993104041757 -0.1767505818480798 0 +0.04235076479157155 -0.125319444738563 0 +0.01856881208261634 -0.1581161122462484 0 +-0.08954662691552559 -0.1264571047816045 0 +-0.005452121800446699 -0.1155011472582572 0 +-0.1143343660278926 -0.1410400898088161 0 +-0.03894283960943228 -0.1695468307455177 0 +-0.0652581424753411 -0.1445756160110129 0 +-0.03052085573967223 -0.151947023306557 0 +-0.06788077304359193 -0.1874096289705951 0 +-0.1331958910977663 -0.152610885744632 0 +-0.08581268036235024 -0.1132784658730372 0 +0.0431004495443762 -0.1750089166706907 0 +0.04954626606539149 -0.1871069973916702 0 +-0.1228756900248168 -0.1682055371358895 0 +-0.1176994853494724 -0.1568144405649703 0 +-0.1073590299120573 -0.1320339536393325 0 +0.002840557139140128 -0.1950089524932584 0 +-0.07730926761527272 -0.1132736452032587 0 +-0.08082051303546661 -0.1660304501628967 0 +0.08221800540391908 -0.1307965272547016 0 +-0.1054772437224605 -0.168719650981541 0 +-0.156123133382318 -0.1126082762917383 0 +-0.1561246900683007 -0.1873910359471928 0 +0.001026500237990171 -0.1267882435102252 0 +-0.1135038284991375 -0.1868136215124755 0 +0.05702790750497383 -0.1122319105264213 0 +-0.01266830024523565 -0.1621090441506543 0 +-0.0800515782999538 -0.1537752061620656 0 +-0.1553813396673815 -0.1425815033315806 0 +0.0779666685747608 -0.1848650231745475 0 +-0.113075185085578 -0.113456791299524 0 +0.05974109556677254 -0.1633261941264472 0 +0.06674614539845977 -0.1151970296775297 0 +0.05739642068904385 -0.1947331390783758 0 +-0.05579493802704617 -0.1734439789779088 0 +0.08302635738898664 -0.1748051454838944 0 +0.1160998187928236 -0.1265831756395432 0 +0.1017522928245965 -0.105491948951982 0 +-0.1181059907475353 -0.1336771456157331 0 +-0.1147899613849459 -0.1942430780653755 0 +0.09290383410739607 -0.1811201694524193 0 +-0.146912014234938 -0.120453383219587 0 +0.1049243117122795 -0.1150711533318517 0 +-0.02976844483970103 -0.166296591240738 0 +-0.1471135141730241 -0.1794663551255734 0 +-0.02524059380499281 -0.1236476029402874 0 +-0.1149010969835807 -0.1057582419095408 0 +-0.1321947430646127 -0.1049563903758641 0 +0.1041370024060695 -0.1715728471655072 0 +-0.1322659856348907 -0.1950640569882987 0 +-0.05751210320552849 -0.1577324954043586 0 +0.02938495633838699 -0.1055885130276571 0 +0.1407804838161112 -0.1861314790369058 0 +-0.09835404645945992 -0.1398903451379551 0 +-0.07909025852691678 -0.1877316021305343 0 +-0.1366053191303957 -0.1844820498200806 0 +0.1371591195753259 -0.1051556378214176 0 +-0.1189001150846669 -0.1226934953548193 0 +-0.0851744774858736 -0.1870516489254272 0 +-0.1229828398308827 -0.1951439136513174 0 +-0.07009740177544238 -0.1282573724842756 0 +0.05240030703460947 -0.1444925553683162 0 +-0.01891439400853129 -0.1288185682264874 0 +0.06818247088514209 -0.1879213430186257 0 +-0.1226002472336686 -0.132287979709674 0 +-0.155207609769864 -0.1226854362266958 0 +-0.1545641535581213 -0.1766244394475679 0 +-0.0701447391231035 -0.1717651051745948 0 +0.1146077694231451 -0.1755062870279124 0 +0.1118545462482397 -0.1706408170386648 0 +-0.1230605078379418 -0.104848707709986 0 +-0.02610254026376531 -0.1363713533448776 0 +-0.1151996852961058 -0.1508095403702329 0 +0.1379511553082533 -0.1651547936734184 0 +-0.02062084081389182 -0.1562075654903347 0 +-0.06749223607765105 -0.1123619484127625 0 +0.09036778536024112 -0.1249901030483477 0 +0.08419890261522076 -0.1199162081780397 0 +0.1218631794768188 -0.1555776730569989 0 +-0.03392009678133627 -0.1313836075747581 0 +-0.101453987859236 -0.1717651957912149 0 +-0.1472391040980854 -0.1602279377234284 0 +-0.1332682989825279 -0.114977364964919 0 +-0.06109067000405102 -0.1755997772045245 0 +0.09905704706265564 -0.1257754083725865 0 +0.03289998912200438 -0.1947678745508293 0 +-0.07740119502665779 -0.1222922945002432 0 +-0.03423911415942491 -0.1226974607626147 0 +0.0378545197197999 -0.150854076330255 0 +-0.09656739973733436 -0.1873646951318903 0 +0.1174263850364805 -0.1948684681356699 0 +-0.1121050403811534 -0.1239284922688873 0 +-0.0209159414280156 -0.1065401623038664 0 +0.07173110139716563 -0.1529496973986387 0 +0.0275712232133345 -0.1521442543938329 0 +0.06803623715632134 -0.1390046778052053 0 +0.0787720312461353 -0.1391550261582456 0 +-0.1389156755441019 -0.1331456628203219 0 +-0.1482119053419292 -0.169280362054621 0 +0.1031491777067808 -0.1369688862117888 0 +-0.03640007583557708 -0.1509146676498758 0 +0.07522794069360716 -0.1577360923389251 0 +-0.05866842021533065 -0.1201800731381805 0 +0.01726796401597146 -0.1526347077383655 0 +0.1026517932267926 -0.1956150670512441 0 +-0.05360681591879057 -0.1277778563445452 0 +0.1470963907556127 -0.1047700196844017 0 +0.01273274232844674 -0.1048143017229111 0 +-0.1242449953393701 -0.1469106004558365 0 +-0.04374891453043445 -0.1730865037525408 0 +-0.07646182670403075 -0.1805708012730227 0 +0.1552419480036255 -0.1273429437812295 0 +-0.1138194786773714 -0.1606810251584715 0 +-0.007064770946318324 -0.1949316348112814 0 +-0.1482624613624054 -0.1314342206022726 0 +-0.03444597354286714 -0.141346918819223 0 +0.08888437201925219 -0.1651895901566734 0 +0.01003905754156707 -0.186692688865543 0 +-0.02777364487424904 -0.1474606029323001 0 +-0.1481918942994551 -0.1945411740106021 0 +-0.05686267132583812 -0.1476540064936182 0 +-0.1474827518680051 -0.1394883857772573 0 +0.08232922859135018 -0.1498613918902719 0 +-0.09767505009220685 -0.1616309943514084 0 +0.1457234298877281 -0.124715013077884 0 +0.1409438711511417 -0.1125558037924242 0 +-0.1482006176833622 -0.1054562416137708 0 +0.0654683398336713 -0.1607419664315773 0 +-0.02016013396121671 -0.1658802369505154 0 +0.008144112584103186 -0.1616107956518214 0 +0.09229617297633269 -0.1470365560381259 0 +0.09577314107434112 -0.1425391972625604 0 +0.07633645164771424 -0.1748736427511706 0 +0.07366757739998708 -0.1668079288445541 0 +0.1552799565406695 -0.1377508418786219 0 +-0.006390094277193322 -0.1883748397517793 0 +-0.07609271976550083 -0.1174186629321 0 +0.1174821699148492 -0.1488955322250377 0 +-0.09601918990741956 -0.1348141889484419 0 +0.04548649591768263 -0.1363899031893473 0 +0.04185324988489889 -0.1952952836469812 0 +0.03429458793036036 -0.1760626928721069 0 +-0.1339531079845972 -0.1318119560074971 0 +0.03724899871018496 -0.11360966509115 0 +-0.1075385691381693 -0.1139322204741553 0 +0.01897811726962275 -0.1796812557395434 0 +-0.002096525286299221 -0.1593879522748424 0 +0.000721039006094525 -0.1744211863418015 0 +0.07923509444885832 -0.1265917506348439 0 +0.04631451202109498 -0.1432437881440702 0 +0.06001971522415708 -0.1875865028692516 0 +0.08516261376531785 -0.1547033164355949 0 +0.06465193971776752 -0.1203475009653999 0 +-0.040322443261608 -0.1548214503422365 0 +-0.01446718531302804 -0.1124142123387347 0 +0.1186264598029636 -0.1648479737728087 0 +0.01380078713103479 -0.1761310906584655 0 +0.05090402432121542 -0.1300421476085272 0 +-0.1425316955803267 -0.1703468185579259 0 +-0.1415737216523943 -0.1228552941618316 0 +-0.03245699603787546 -0.1847267668174132 0 +0.07356010277143876 -0.1051602742840499 0 +-0.02973197930461799 -0.1947010309982067 0 +-0.0966299862863263 -0.1126589676789884 0 +0.1402820106619919 -0.1327332770273634 0 +0.1062338107128222 -0.1452768581899962 0 +0.01790844349327678 -0.1854578327893876 0 +-0.1354310317930081 -0.1587337838546847 0 +0.06632201201257631 -0.1704500618117308 0 +0.06619029694104628 -0.1546765626489685 0 +0.1273076146917022 -0.1956534959476313 0 +0.01504148521501772 -0.1454524915499691 0 +0.1363562922866814 -0.1246706707055643 0 +0.03530473305842135 -0.1806690074211292 0 +-0.05185481255244941 -0.1048415912308403 0 +0.06890588325149301 -0.144883306265178 0 +-0.1128782450680422 -0.1695731424469905 0 +0.08638843097623937 -0.1449010812435678 0 +-0.1312430860592301 -0.1894240754371826 0 +0.01255910433335365 -0.1949074792054483 0 +-0.1335718245941736 -0.1688370629191342 0 +-0.1238354373361564 -0.1892915701039669 0 +-0.1067092608597396 -0.1372388929071165 0 +-0.1052022701296162 -0.1633581090760768 0 +0.05081799563875662 -0.1697276645470616 0 +-0.03159814344635511 -0.1048849748828446 0 +-0.01764686572873291 -0.161659633760481 0 +0.03922925887240895 -0.1052960347920677 0 +0.1361370750150419 -0.1474978397745725 0 +0.1489503618762281 -0.1435247947876622 0 +0.112568232209336 -0.1503582122845992 0 +0.09205703646573245 -0.1587115521920485 0 +0.05557543677050918 -0.1594509527392482 0 +-0.01484278868199148 -0.1731101604450558 0 +-0.1241662329108426 -0.1104067679084325 0 +0.09940229118185441 -0.1871223261070469 0 +0.1375 -0.1954483603865426 0 +0.1228047572407206 -0.171669167353957 0 +-0.0966009892927667 -0.1696964711076209 0 +-0.09205532213027554 -0.1456950313538467 0 +0.08712127523471698 -0.132141323809438 0 +0.0267415272133014 -0.1136149001426518 0 +0.02298893386817965 -0.1607663519044358 0 +-0.1384952451859018 -0.1952581531413512 0 +-0.1380950744039686 -0.1775853590648244 0 +0.01457060988153679 -0.1188937748352539 0 +-0.05220649675551022 -0.1957537623313684 0 +0.03801559097121109 -0.1723063736714856 0 +0.1256524913860771 -0.1471320921483046 0 +0.1114760762678734 -0.1050334888846759 0 +-0.1072796151258353 -0.1866679772823792 0 +0.1465516635009305 -0.1348150804663505 0 +-0.05942432295884824 -0.1305210959772045 0 +-0.1385222881047671 -0.1049509031908144 0 +0.007193900857483064 -0.1478029779062804 0 +-0.09345628096182612 -0.1956712900184321 0 +-0.03697109498761541 -0.1874002703866416 0 +0.1461161912031911 -0.1199630235735764 0 +0.05900339025166038 -0.1825344726090363 0 +0.0654235369671016 -0.1309492828771136 0 +0.06928836448751123 -0.1242411641261203 0 +0.1098307278599885 -0.1871085463223253 0 +-0.0873741264677196 -0.1487248038602738 0 +-0.03691637911199816 -0.1122928282972294 0 +0.1021541353822182 -0.1492131129364833 0 +-0.09325426731655038 -0.1043552320844854 0 +-0.0497114398048859 -0.187482330102467 0 +-0.1247530223221124 -0.1719625985409004 0 +0.1549125982788527 -0.1601629978914889 0 +-0.01480404552674025 -0.1208926511963859 0 +-0.02594267836080841 -0.1571503286241832 0 +0.02149101498115073 -0.1045890600946515 0 +0.0008107167671534179 -0.1320498925975399 0 +-0.04782839821816183 -0.1696394549599875 0 +-0.04970932125849106 -0.1650724941304841 0 +-0.1088379530442816 -0.1598535148503147 0 +0.01388651494537095 -0.1104137490477888 0 +0.03133834886012397 -0.1262322215376052 0 +-0.001495043149941522 -0.1504236089164963 0 +0.08244091919155426 -0.1957543335352384 0 +0.111774790947499 -0.1952978525146449 0 +0.02109790139180235 -0.1274154290339461 0 +0.13269500959113 -0.1889139729130734 0 +-0.1388100932780366 -0.1140461577756095 0 +-0.03338256116348744 -0.1696256420498507 0 +0.04991661691384276 -0.1603664957022186 0 +0.0598591374240018 -0.172794682130991 0 +-0.1236364130718397 -0.1271476421043925 0 +0.05134840857670477 -0.104695181927692 0 +0.02297403624883324 -0.1889563787385669 0 +-0.08492851373150637 -0.1794404000553855 0 +0.1404936080481042 -0.127373229624278 0 +0.01403042221308112 -0.1632187565321211 0 +0.1557767557075996 -0.1041852149782404 0 +-0.04792500395779613 -0.120483519272951 0 +0.1098789060201077 -0.1110982407867057 0 +0.1177654731093552 -0.1044964449855123 0 +-0.04287685408925458 -0.1955860304084127 0 +0.1107126361817571 -0.1610988127390122 0 +-0.1098075442024258 -0.1413322222889066 0 +0.148551401306021 -0.1956700798629942 0 +-0.128634400399766 -0.180788273174055 0 +0.001352215374411808 -0.1424817130789144 0 +-0.0006671902664272092 -0.1170320779946626 0 +0.1549392484100224 -0.1198847167120944 0 +0.04216294994141868 -0.116617668123967 0 +-0.1472210037764943 -0.1150079072686877 0 +-0.01323709598507067 -0.1955109750525115 0 +0.1145898638854332 -0.1852132150472957 0 +0.03730081764972776 -0.1554208466848419 0 +-0.09807583040510962 -0.1503760405827308 0 +0.1101668789050104 -0.1293826323243438 0 +-0.09189848662721876 -0.1560270610462479 0 +0.01166019520612242 -0.1717761739326749 0 +-0.1471461723118248 -0.1849893433118059 0 +0.09115487187646644 -0.1047963124873771 0 +0.07256000785633529 -0.1620890076329673 0 +0.1562673934434945 -0.1769336413888752 0 +0.1316079904704927 -0.1042149156012681 0 +0.0862472061198835 -0.111055714690145 0 +0.129578296728891 -0.1295539376889642 0 +0.0944110256808733 -0.1946724966447673 0 +0.146789737010653 -0.1099121799380409 0 +0.09994003785919323 -0.1168655278097574 0 +0.0405158108048268 -0.1894372161697923 0 +0.1146808230510297 -0.1218162954402786 0 +-0.03135855019602807 -0.1148774142669126 0 +-0.006314197932738496 -0.1247367913375822 0 +-0.1309795983875301 -0.1100821320218208 0 +-0.03431214942241342 -0.1950858158869125 0 +0.10747141495242 -0.119779456001739 0 +-0.04258770135732853 -0.1042629353710066 0 +0.01998711220337829 -0.1184160821016988 0 +-0.1441318341455551 -0.1547712610942919 0 +0.1179897335072644 -0.1130298182009822 0 +-0.01441792867360734 -0.187015461310799 0 +0.1462900477073238 -0.1595989625444375 0 +-0.05292364941005792 -0.1831977435606339 0 +0.02311124786865162 -0.1229839285307138 0 +0.08657275489011261 -0.1875284120779731 0 +-0.04817335692146183 -0.1405691333791849 0 +-0.09281231604779093 -0.1842241301351819 0 +0.1553410632181959 -0.1121171026213968 0 +-0.1294373007218751 -0.1183536011786976 0 +-0.05156973868549249 -0.1777274365396548 0 +0.03011613072177189 -0.1745377314313448 0 +-0.02877874631504963 -0.1317015610335361 0 +0.05193054258725972 -0.1787496335696867 0 +-0.01214967331524677 -0.1045681965327435 0 +0.1556792776437124 -0.1682096498044976 0 +0.02499695651290379 -0.194856650429052 0 +-0.04327351336651852 -0.1260285346406524 0 +0.06103231125853286 -0.1467704360300884 0 +0.07408417216773601 -0.1224318402723952 0 +0.07285914106757277 -0.184233364424031 0 +-0.1401606918217206 -0.1377612171561833 0 +0.1210863701251392 -0.1175853457581134 0 +-0.1314693660142093 -0.1477099234645138 0 +0.1497750794804934 -0.127500443815893 0 +-0.06783381949795787 -0.1336500670225249 0 +-0.06313519506715427 -0.135118805668907 0 +0.02225979785210567 -0.113590191338197 0 +-0.06287823909593551 -0.1954551147841753 0 +0.004438555084710149 -0.1110484837087696 0 +-0.1082021576123853 -0.1042343088239811 0 +-0.1236020325115433 -0.1410020322087842 0 +-0.0921638352560734 -0.1166474680791743 0 +0.124908572895431 -0.1371159784174743 0 +0.01851590817465813 -0.1424293964759178 0 +0.03257053989764563 -0.1900564499702571 0 +0.1016016793256993 -0.1616178223136845 0 +0.04344587783164375 -0.1794633878751896 0 +0.1373691789994131 -0.137763546255294 0 +0.07378821306140174 -0.1956628521737946 0 +0.02852776661360075 -0.1667889342675709 0 +-0.03396209644919375 -0.1777341934865592 0 +-0.06043192103740503 -0.1539865907787034 0 +-0.02982874619124873 -0.143487835267185 0 +0.03180838750067808 -0.1376140241358554 0 +-0.003066716565246585 -0.1400162249769344 0 +0.005543203042749696 -0.1661917920704969 0 +0.04629396008357113 -0.152121902798765 0 +-0.06845978881958162 -0.1791695056175992 0 +0.06644686791136672 -0.1794469612040556 0 +-0.1395393726909331 -0.162422928827205 0 +-0.1083313061519581 -0.195581133192669 0 +0.1481619717672318 -0.1751881930149677 0 +-0.09507450605402473 -0.16512886566674 0 +-0.01149934681739762 -0.1297288407286157 0 +0.1178902311675409 -0.1413091595742993 0 +0.1355549503591037 -0.1545131175485848 0 +-0.08131106404467957 -0.1046506470097652 0 +0.007989061195054565 -0.1038819987098494 0 +-0.0973461378669359 -0.1296797568049245 0 +-0.008718535579365761 -0.1205521571376738 0 +-0.02171327624201207 -0.1959275468035117 0 +-0.07240087647033663 -0.1954848404230079 0 +-0.0485443388809077 -0.1571963561630793 0 +-0.02120098000347139 -0.1448361869589882 0 +-0.07252717122523937 -0.103835282028205 0 +-0.02456606362615359 -0.1657928954012406 0 +0.02055015499541893 -0.1688946346889588 0 +-0.07058325675469784 -0.1416069784172488 0 +0.02543642700221211 -0.1805849482269812 0 +-0.09336421234126362 -0.1223326460328072 0 +0.1420406420998945 -0.1173588453300768 0 +-0.1069785873337968 -0.1459810980040805 0 +-0.03417023761564528 -0.1600798287291717 0 +-0.1382808449089031 -0.1543311866230934 0 +-0.1319465664489156 -0.1618560991805163 0 +0.02715299183344365 -0.1394555355614636 0 +0.02607626962744168 -0.1572046927789094 0 +0.06706240158046242 -0.1101505407830914 0 +-0.06237498411084747 -0.103780132213875 0 +0.1554322135185142 -0.155587049812121 0 +-0.1326593502441368 -0.1396465364582631 0 +0.01277527576784492 -0.1356578409051337 0 +-0.01765485619615527 -0.1818676080846293 0 +-0.138492826075606 -0.167437952045711 0 +0.09803573735501618 -0.1692125186167161 0 +0.09409117326215335 -0.1897603335936487 0 +0.1139394063977277 -0.166014293229389 0 +0.1486095474111465 -0.1835249198996326 0 +0.1435771762407072 -0.1682469096596812 0 +0.06926321700724102 -0.1758060926371066 0 +0.09469970445749423 -0.1109563945109729 0 +-0.1324906694942647 -0.1840570149682937 0 +0.09492372743913854 -0.1346789298873005 0 +0.05823754725627042 -0.1356275737398958 0 +0.1557613855564062 -0.1889763725929363 0 +0.0408331703136914 -0.1362952669196003 0 +-0.1074426465899834 -0.1552098798947407 0 +0.1417809999673891 -0.1484699765918504 0 +0.02372230312900888 -0.1359233975608724 0 +-0.07508852622069372 -0.1556441783466106 0 +0.05027376404757769 -0.1154213090131417 0 +-0.1017866200905888 -0.1448531997143448 0 +0.01779449753372151 -0.1961961427164696 0 +-0.1022344313887829 -0.1818617969685948 0 +-0.00750379298167244 -0.1037878048931076 0 +0.1492661083679987 -0.1521211065463202 0 +0.08359543615610034 -0.1411237158810685 0 +-0.048293102401118 -0.1482268947334359 0 +-0.06037398504114818 -0.1812087497158436 0 +-0.08260281501056012 -0.1960908313779317 0 +0.1305784592857876 -0.169814634542995 0 +-0.1104817828126596 -0.1785794428228266 0 +0.0291336355507395 -0.1177712783156982 0 +0.08797984878402257 -0.1830854233776809 0 +0.103223034117905 -0.1907754118573669 0 +-0.0552919891191547 -0.1322660234024795 0 +-0.08536032000262342 -0.1182172454305447 0 +0.03028058468215818 -0.1100057185769255 0 +0.07893903939866989 -0.1893106900469485 0 +-0.04055829283468788 -0.1646914065665958 0 +-0.09337135466149685 -0.1780790825800809 0 +-0.1355935697359594 -0.123124558930013 0 +0.1041923348185956 -0.1238615106770444 0 +-0.06505539273484523 -0.170561248922117 0 +0.1270223338638381 -0.1554621997714793 0 +-0.04321805616258129 -0.1908148136105031 0 +-0.01603784243944301 -0.1254972766064743 0 +-0.08311697671779036 -0.1342692423580241 0 +0.01516887084994951 -0.126821255404236 0 +-0.03976419321435864 -0.1384898214765313 0 +-0.1023212957075863 -0.1543136604466164 0 +0.09771872046258742 -0.164505026173222 0 +0.0625 -0.10369247574089 0 +0.01175591453760942 -0.154299597002152 0 +0.0766282828270419 -0.1434526451468593 0 +0.003785376533938632 -0.1574326821781634 0 +0.006942050413345302 -0.1258140546619263 0 +0.09659698230764696 -0.1774131508222081 0 +-0.06148830544570486 -0.1402749430570065 0 +-0.07655944248802996 -0.1642658148330811 0 +0.07800795872556376 -0.1481317054025007 0 +-0.1175914998696475 -0.114464652399147 0 +0.1319556108983347 -0.1256497595969778 0 +0.1058455074030351 -0.1633538621309233 0 +-0.1560405102380547 -0.1377264167346676 0 +0.02503823667385019 -0.1312692695974892 0 +0.07416739024866263 -0.1109225925001956 0 +-0.1315857254202221 -0.1354260332304905 0 +0.02411119911057406 -0.1653168461951818 0 +-0.002343956118098234 -0.1963719835343505 0 +-0.1444850457970728 -0.1436171682349638 0 +-0.1561377058149025 -0.1727061829998768 0 +0.003554364872442661 -0.1829642410088305 0 +0.005087098731566751 -0.178229565999571 0 +0.1239546357827947 -0.1882336641830627 0 +0.02291833069928028 -0.1450554588402805 0 +-0.01688154628839254 -0.1531558585990694 0 +-0.1555930941780469 -0.1653003870995118 0 +0.09279109960914145 -0.1387737519142421 0 +0.1114140963324048 -0.1356086164626235 0 +0.1352983324903216 -0.1693516363010054 0 +0.102428852989968 -0.1327473028751444 0 +-0.0453702262068111 -0.1121160030282541 0 +0.06223841833254799 -0.1118340323769497 0 +-0.08518780323704891 -0.1750101262346887 0 +0.07253386479035295 -0.1358784480339081 0 +0.08747161289395967 -0.1962819079281649 0 +0.05670775374752962 -0.116849367757468 0 +-0.01396564176035545 -0.1782227535551287 0 +0.1282541998845719 -0.1638909740517944 0 +-0.1560672967472097 -0.1520214083897982 0 +-0.02414773677791599 -0.1877580472338712 0 +0.0343163164592625 -0.1462379742060624 0 +-0.08729788933449258 -0.1602436515236238 0 +0.1046295558302103 -0.1541362982881591 0 +-0.004412807795644669 -0.154557826704491 0 +0.003858146571246585 -0.1517856782606287 0 +0.08160977812908896 -0.1045011633351447 0 +0.01062000370343034 -0.128682446560414 0 +0.1560938826841988 -0.1478370154042645 0 +-0.04793245258323724 -0.1296497743976462 0 +-0.1185387678193109 -0.186022721242964 0 +-0.01018697991912396 -0.1858338816392361 0 +0.0001060763636617028 -0.1218357941460556 0 +-0.00306894420101616 -0.181338489916436 0 +-0.01953989691181023 -0.1331462924873935 0 +-0.04402503879476118 -0.1170530486625034 0 +0.139644513367007 -0.1559912778370844 0 +0.1401738822136404 -0.1820269893746852 0 +-0.1106634035881208 -0.1833672998533704 0 +0.123630512795854 -0.1417826239745022 0 +-0.06195216343914758 -0.1657617921138929 0 +-0.04664683398633677 -0.1616208578557207 0 +0.06520803455774957 -0.1956693050995045 0 +-0.0832443848742257 -0.1451100020003551 0 +-0.00935274020334723 -0.1120481909849972 0 +-0.004634584803925582 -0.1105415943832326 0 +0.001681704681714877 -0.1902878584656487 0 +-0.05607326816312522 -0.1164000552225193 0 +0.04055205107401845 -0.1629916248121074 0 +-0.06242128223371902 -0.126928129261084 0 +0.122376361475606 -0.196540761527149 0 +-0.05218335140835215 -0.1234882959742839 0 +-0.1106077549275624 -0.1169157092436299 0 +-0.05804006321320018 -0.1895494219265669 0 +-0.1561872809046969 -0.1825732602591567 0 +-0.1561239323477625 -0.1173385498983475 0 +-0.06866026901528088 -0.1208260490558064 0 +0.1557541672795069 -0.1957541672795073 0 +0.1182591489480153 -0.1898424364095012 0 +0.0933291531052812 -0.1629004639540566 0 +0.06429805126216269 -0.1652537575906974 0 +-0.04203008700560169 -0.1094355511627688 0 +0.08164033309311605 -0.1100868857681394 0 +-0.1002531112567673 -0.1170733986151839 0 +-0.0466307347737234 -0.1335443986042108 0 +0.06848010319691582 -0.1831023308414132 0 +-0.1561661400890819 -0.1476246439380559 0 +0.156004643138406 -0.1326059389838275 0 +0.156160571286354 -0.1427745997099985 0 +0.1058455302197865 -0.1677358479474187 0 +-0.007779270186761764 -0.171988208819386 0 +0.1274051836572047 -0.1781209795020653 0 +0.04943421352149242 -0.1204209629565152 0 +0.05270993012437732 -0.1233783096049831 0 +0.1246206757663975 -0.1290466871810214 0 +0.04827238325389872 -0.1651543386419736 0 +-0.1003445469735689 -0.1043000782732303 0 +0.1311802920480473 -0.1113784685061082 0 +0.1268126540293006 -0.1118188950648214 0 +0.1379869944858764 -0.1744453410333451 0 +0.1040333219895186 -0.1762815487409095 0 +0.07169822353997581 -0.1152810707094803 0 +-0.0753600616799515 -0.1858998133476218 0 +0.08805252486557903 -0.1745047316216348 0 +0.08357379122939937 -0.179875340333321 0 +-0.1482435650111766 -0.164763978308459 0 +0.1256389173527387 -0.1042004152398731 0 +0.08844823549971065 -0.1212040326740383 0 +0.09544998350799971 -0.1851053895747946 0 +0.1510767812054262 -0.188428700179753 0 +-0.1563241800004471 -0.127557215309628 0 +-0.03085741685697511 -0.1562375559128816 0 +0.1562665057766035 -0.1812227277128336 0 +0.03481595480167362 -0.1407618881900337 0 +-0.1453208665318911 -0.1242454822601701 0 +0.008261350627493991 -0.1135159620677381 0 +-0.04748789471231622 -0.1966740244268436 0 +0.1325422791265307 -0.1157172994420603 0 +0.1135285746489465 -0.1142491462447455 0 +0.00916854209553461 -0.1211599908761672 0 +0.04137960731671288 -0.158969429574654 0 +0.1159805064819951 -0.1357405163934173 0 +0.04664769267292937 -0.1958720418273286 0 +-0.0472182782237693 -0.1032904687311868 0 +0.1073172769084883 -0.1035235974506628 0 +-0.1368918491169376 -0.140098440433633 0 +0.09475329381532521 -0.1269267303989706 0 +0.04991586976447712 -0.1348487015105179 0 +0.1278461992062289 -0.1823222383246903 0 +0.09134785116716149 -0.1702470571356875 0 +0.08761133675760358 -0.1395122774360829 0 +0.04000103257792954 -0.1218768340150123 0 +-0.01007649208680624 -0.1798241334010811 0 +0.1317399082510874 -0.1406699948291824 0 +0.03291288561549066 -0.103293847599445 0 +0.1023643277833841 -0.1831913447242253 0 +0.1496450816088283 -0.1132487512531089 0 +0.09927550171326061 -0.1215332073024545 0 +-0.0458374438787124 -0.1781547988883753 0 +-0.08553762622962459 -0.139830600857252 0 +0.07321530256720135 -0.1311914088394897 0 +0.04366061444946143 -0.1049334463085032 0 +0.05344582234116883 -0.1961142335360803 0 +-0.04428528896633644 -0.18312156775872 0 +0.06152577670143861 -0.1395849698395699 0 +-0.1558611564126065 -0.161234452688536 0 +0.08949565835634084 -0.1548828870521167 0 +-0.08769469370195743 -0.1681250849750895 0 +-0.03828060058366595 -0.1227692784834017 0 +0.07503016621880672 -0.17964547472404 0 +0.04524522987627314 -0.157420191275937 0 +0.1284094527373558 -0.1507931680283657 0 +0.1453096448401064 -0.13965637027029 0 +0.0614347939710727 -0.1781478885240799 0 +0.06404589546881019 -0.1883093185427208 0 +-0.10048847880419 -0.195877440773139 0 +-0.05153130853746066 -0.1910867238506209 0 +0.09817331011983199 -0.1964238045021154 0 +0.1422903561893637 -0.1034805681849867 0 +0.121630553701186 -0.1675538919478801 0 +0.01044997957042617 -0.1441840756652171 0 +-0.01719124842886375 -0.1398356037460393 0 +0.1341967883516396 -0.1772410501879165 0 +0.03509841533062154 -0.1224146362447988 0 +0.06918119276883812 -0.1285942071241762 0 +0.05381409590949791 -0.1381374637036548 0 +0.1275967520122137 -0.1907543073447321 0 +-0.01698858059220983 -0.103560693574351 0 +0.1040712366813489 -0.1104266092989852 0 +0.05794478833821172 -0.1673714206188713 0 +-0.02037636998567923 -0.1914175061516623 0 +0.1318064654933385 -0.1841176015723194 0 +-0.04473913679858735 -0.1545419248625619 0 +-0.1492307890064638 -0.1505384087528044 0 +0.04306772559761486 -0.17014496942624 0 +0.08675599227858416 -0.1039070800785188 0 +0.03360704953860227 -0.1178712185879515 0 +0.02213907406321715 -0.172849409095638 0 +0.1503671540540217 -0.1612210251176616 0 +-0.08626965995623215 -0.1833552199434363 0 +-0.05201959738040401 -0.1491636967310259 0 +0.0596028079809808 -0.126833422878314 0 +-0.08691254365808984 -0.1099891657142364 0 +-0.1373695320051699 -0.1184246817606954 0 +-0.08167514728089487 -0.1264458625167861 0 +0.01764933513218774 -0.1301345527246782 0 +-0.1517288821825501 -0.1409880248994124 0 +-0.1405416291227504 -0.1468744252700728 0 +0.01855511329506108 -0.1898726787174854 0 +0.04550410914513398 -0.1868623259243739 0 +-0.1054689669876154 -0.1222971347173757 0 +-0.08808222214506747 -0.1319665171478145 0 +-0.07476573861161859 -0.1301902663162685 0 +-0.1010151210210529 -0.1090198881697702 0 +-0.1029025896521345 -0.1395435323024144 0 +0.09085719312922502 -0.113798234896286 0 +0.03347740916024867 -0.1616673874295996 0 +0.129126484416735 -0.1368303715641864 0 +0.007319302761430301 -0.170796739957911 0 +-0.1182771429928661 -0.1961335280691781 0 +-0.09120408845952489 -0.1355293906491126 0 +-0.03984898320585775 -0.1306857239419181 0 +0.1144856889872646 -0.1583647356496952 0 +0.1225040901199514 -0.1333250117777125 0 +-0.09373633551440264 -0.17293983605287 0 +-0.1011365862583418 -0.190833220504225 0 +0.04741020971061646 -0.1770194821091238 0 +-0.04337034877556183 -0.1415497092522367 0 +0.04127448496574729 -0.1438209574006399 0 +-0.05160908874592596 -0.1724867584481398 0 +-0.07245557416850903 -0.1485064766352342 0 +-0.03753223046571125 -0.1463343237592193 0 +0.02258108052082521 -0.1497707665549336 0 +0.004640754275691826 -0.1339854641493467 0 +0.1511779912572074 -0.1683553319545775 0 +-0.1052471643649918 -0.1103447070661056 0 +-0.09078386548234506 -0.1644173356315014 0 +-0.05693141981946958 -0.1394284236747392 0 +-0.09359461618420681 -0.1273374783370901 0 +-0.02200363783850969 -0.1736529943574806 0 +-0.01189132473439414 -0.1525822977461341 0 +0.01055506096018753 -0.1787873882583602 0 +-0.02968997010346915 -0.1702793253517066 0 +-0.05716061631247123 -0.1681426657770184 0 +-0.1511196894351913 -0.1587085815786924 0 +0.07887337403047184 -0.1676262724444374 0 +0.08292638914827477 -0.1694965516797169 0 +0.1479768019318296 -0.1912828713112668 0 +-0.05236718524673492 -0.1561578965088677 0 +0.1513260306101761 -0.1037638039072492 0 +-0.1157899274317802 -0.1253266142679662 0 +0.01726272771775576 -0.103253336665433 0 +0.1357409285990478 -0.1339415836375024 0 +0.1111619405613675 -0.1421498547233929 0 +0.06131189908186069 -0.1959574711222246 0 +0.0283438371382608 -0.1713980684204912 0 +-0.03733628095106783 -0.1035475686034059 0 +0.02887508744004781 -0.1301465917350835 0 +-0.1213439986174079 -0.1741246869415346 0 +-0.07772277744061019 -0.1758030474987307 0 +-0.1392986441219629 -0.1872372029273594 0 +0.08239333806993487 -0.1614454559460299 0 +-0.1183868636552093 -0.1039170442095162 0 +-0.1562706133148148 -0.1334691483740817 0 +0.09697490622695723 -0.1559531651557082 0 +-0.06243919436041462 -0.1131471376597613 0 +0.1335804786615839 -0.1507201466426191 0 +0.02697648986510565 -0.1218732637679956 0 +0.1100324620960139 -0.1469088703625979 0 +-0.02339568970865194 -0.1482023334527432 0 +0.1194985200779473 -0.1089773752280127 0 +0.1010531520753185 -0.1573956774729036 0 +0.05163494970169569 -0.1531458958508424 0 +-0.1457400242515744 -0.1724090249873042 0 +-0.1091960155630921 -0.1707495825563923 0 +-0.06414679674590429 -0.1783350377046165 0 +0.03880980645212527 -0.1399602015582415 0 +-0.04951260744484421 -0.1365009730012982 0 +0.01952712137909264 -0.1097664194919062 0 +-0.1506304860707207 -0.1781266172675409 0 +-0.1507738432654284 -0.1221216153487737 0 +-0.02611029253714448 -0.1963091534280817 0 +0.1303779070234806 -0.1757223532304455 0 +-0.1282312095037579 -0.1262091359405761 0 +0.08146421279552601 -0.1537276584465522 0 +-0.02302273118183514 -0.1269888612488013 0 +-0.02785248478835817 -0.1903572189920621 0 +0.02564029529298064 -0.1039107745356188 0 +-0.04953162795717363 -0.1103816926544397 0 +-0.1407890196258754 -0.1099772162533707 0 +-0.09314816572866068 -0.1083890259743708 0 +0.1257544388272137 -0.1158124863298769 0 +0.1399551727429084 -0.1407843165172195 0 +0.09630417498261042 -0.1511022493204406 0 +0.1192137452796394 -0.1596427413018101 0 +0.1424811443619832 -0.1632534939481247 0 +0.1126132750256883 -0.1795846754588353 0 +0.07573593824136843 -0.1704783690463698 0 +-0.05388134150248144 -0.1648348748401567 0 +0.1414482433722304 -0.1964885279068058 0 +-0.0355964064911756 -0.1375573539276155 0 +-0.1478925863924487 -0.1355157616263157 0 +0.04539009123751755 -0.1098194722245351 0 +-0.04219003082982312 -0.1341751235725541 0 +0.05426696371037393 -0.1743202259356263 0 +-0.002562334539732279 -0.1247335820793095 0 +-0.1245123393560653 -0.1527493564538757 0 +-0.08474908436980486 -0.1530169002904826 0 +-0.0007041795222966698 -0.1692570919058133 0 +0.1514176368695494 -0.1342728477533263 0 +0.1511531235197003 -0.1482444545280805 0 +-0.1171001136080723 -0.137739846419463 0 +-0.02164015540247259 -0.1409181170747973 0 +0.1325687248049472 -0.1966630067175592 0 +-0.02156358724765756 -0.1151944546453579 0 +0.00866996533519822 -0.157344723263381 0 +-0.1428446666621246 -0.1966897392694848 0 +-0.04178651510852169 -0.1451458404607846 0 +0.1488807930464916 -0.1313694608723575 0 +-0.1246517125746336 -0.1808309169160126 0 +-0.1050058654807094 -0.1898745850938937 0 +-0.1016160925139571 -0.1615326759921155 0 +0.07763182631393423 -0.1034873386306509 0 +-0.1428585960913956 -0.1033345049103377 0 +-0.06396214994154696 -0.1860161295648854 0 +-0.05814566205351372 -0.1099880846883471 0 +0.1434232390937931 -0.1894573171200133 0 +-0.02915234161919857 -0.1396539630116869 0 +0.07877441350640779 -0.1171385411656585 0 +0.01300193536101533 -0.1148963201194167 0 +-0.122568606226996 -0.1211447934965319 0 +0.0579287394326219 -0.1443843744116423 0 +-0.03999384533706497 -0.1174275830792532 0 +-0.06157678720919533 -0.1231068108711861 0 +0.1366218741701111 -0.1211337047583826 0 +-0.04050328148748543 -0.1828870648877322 0 +0.1383561162450985 -0.1089333657095301 0 +0.1502919153354739 -0.1184197041101016 0 +-0.01664464316889013 -0.1360552731827069 0 +-0.1313149622106781 -0.1653858716553361 0 +-0.1309223181647522 -0.1228255077939519 0 +-0.1343098733015385 -0.1759936576453481 0 +-0.02497175469312412 -0.1104036009975589 0 +0.1563957126862568 -0.1637210811832421 0 +0.02579893627017786 -0.1859588748579842 0 +-0.01200153095935771 -0.1089575318730818 0 +-0.1189292385286548 -0.1479484441788841 0 +-0.08092009491581881 -0.1725950207562507 0 +0.004966339175787766 -0.1737885917252789 0 +-0.1275300627897755 -0.1968126976352734 0 +0.111864756066904 -0.119351656140347 0 +-0.02750000000000003 -0.1029815190791963 0 +-0.006188160208750938 -0.144032261822895 0 +0.09262936079632812 -0.1182690195876233 0 +-0.06761606398517422 -0.158168725373939 0 +-0.1251282349753884 -0.1174431360240708 0 +-0.004970516879843559 -0.1677144501836278 0 +0.00750000000000006 -0.1970322981734242 0 +0.01366208754176041 -0.1853046564719792 0 +-0.1275305013335316 -0.1031839359827673 0 +0.1207046457580239 -0.1819250667550593 0 +-0.0389872930268394 -0.1787701057249041 0 +0.1203353693948618 -0.1519028210325543 0 +-0.1521867073547628 -0.1139891190520139 0 +0.1079914038890957 -0.1701724819712683 0 +-0.1521843953074311 -0.1859961392091045 0 +-0.07593226490812732 -0.1419118873519329 0 +0.0951849868114486 -0.1722118722484374 0 +-0.1056291068981823 -0.1784665595553904 0 +0.1332214844750338 -0.1615390801305391 0 +0.1522812755559613 -0.19679909558678 0 +-0.08111395077379024 -0.1300960548801335 0 +0.02669702011784992 -0.1440531707173272 0 +0.000521008746680174 -0.1038139151042382 0 +-0.1561779045624238 -0.1038095611013385 0 +-0.156176799253591 -0.1961897875291307 0 +-0.1117028632539226 -0.1036143282992406 0 +-0.01820440583426439 -0.1110659995134077 0 +-0.09027230828281665 -0.1403219026959703 0 +0.1174537843370638 -0.145203478035154 0 +-0.06921818941652114 -0.1680534278904226 0 +0.05866276251411229 -0.1035979335263139 0 +-0.09406508581684393 -0.1915048396075586 0 +0.008403988690664397 -0.1393533263713462 0 +0.09819896357615562 -0.1031335468793157 0 +-0.09714842208903784 -0.1967886961725486 0 +-0.1011226701144808 -0.1249088703905339 0 +-0.1233929217362014 -0.1850512742816318 0 +0.0343060840914903 -0.1108761297516256 0 +-0.05579542970956046 -0.1227955775515639 0 +-0.08154378952148207 -0.1137795969249412 0 +-0.03808677861705927 -0.196691067577462 0 +-0.128035383060337 -0.1541699161206381 0 +-0.1298879938091796 -0.1767800043733092 0 +-0.055290667176088 -0.1428737981900965 0 +-0.06133539628622724 -0.1454533820314882 0 +0.02991566702746547 -0.1479233415379837 0 +-0.07095366388589826 -0.1364691098111669 0 +-0.02664033919148671 -0.1277517299159243 0 +-0.01313868417047338 -0.1423903957377706 0 +-0.08745241043178917 -0.18989059493509 0 +-0.06994227184459488 -0.1457563177033772 0 +0.1565061950820489 -0.1165085592055523 0 +-0.1094552708497893 -0.1212176209567246 0 +-0.09825009945538372 -0.1213197507869122 0 +-0.006415326051105158 -0.1585323866690761 0 +0.05640754620179687 -0.1307537345295481 0 +-0.08907570483284022 -0.1525201229344623 0 +0.1290138154963734 -0.1182899050462735 0 +0.02171726036032382 -0.1967151790223046 0 +0.1074213907362012 -0.1970216358755706 0 +-0.1563480437873747 -0.1921425699747183 0 +-0.1563490738666823 -0.1078565554673176 0 +0.1316865317841663 -0.1571826145093438 0 +-0.02894396421180934 -0.1235166287799816 0 +0.08574792278277263 -0.1151185114770197 0 +-0.01532633270612671 -0.1911262862644676 0 +0.03921950242814215 -0.1814501071977417 0 +0.01603970939747779 -0.1487444034079847 0 +0.0915161064581093 -0.1511244548024329 0 +0.03748201450487636 -0.1969827846140033 0 +-0.009760153692670035 -0.1596807703244289 0 +0.1064909101815353 -0.1831232708929163 0 +0.00869313688350719 -0.1513544513506395 0 +-0.09697095823151966 -0.1032689045014389 0 +-0.02683051557148191 -0.1826990133185218 0 +0.08029527395775901 -0.1353819847861122 0 +-0.01154223662720154 -0.1701901881731152 0 +-0.08198934149154746 -0.187590586222885 0 +-0.08375954061160781 -0.1571390737201422 0 +-0.1149375745608604 -0.1904635228290248 0 +0.05893741082868274 -0.191283941022646 0 +0.0165855760707629 -0.1334610117578189 0 +-0.1187085527748903 -0.1410583266397874 0 +-0.152231036017686 -0.153725588615828 0 +0.05890186545782815 -0.1543468160561625 0 +-0.1116993722018346 -0.196396305776539 0 +0.121717060173606 -0.1488654567368111 0 +-0.09797817025951934 -0.1782667030598269 0 +-0.0295532820969624 -0.1763411747177303 0 +0.002111242924860473 -0.1194026078633365 0 +0.0772757169224739 -0.1298087633827655 0 +0.04698081730410317 -0.1723501037368347 0 +-0.02699104909292908 -0.1622143828100387 0 +-0.115041346481985 -0.1098085856886699 0 +-0.1354657691895382 -0.1483720873121482 0 +-0.0114866772484658 -0.1350135691699336 0 +0.005680448150438651 -0.1908474085792023 0 +0.06740758967114178 -0.1351361516363074 0 +-0.05678921491696763 -0.1834146639845425 0 +0.0699270667904506 -0.1686650086358773 0 +-0.07280811030621591 -0.1145533908521982 0 +0.1285952095995974 -0.1225065826448624 0 +0.05366471545438062 -0.1146517637418337 0 +-0.01403926548946388 -0.1464661974474354 0 +0.1246488046848865 -0.1595225056337488 0 +0.02848484288684321 -0.1962836008652409 0 +0.0817713501228757 -0.123241468146105 0 +0.04212767297015947 -0.1508988112600695 0 +-0.03518027705621823 -0.1073590382010424 0 +0.0148863097459179 -0.1726932541312936 0 +-0.07030220787622769 -0.1752016603489094 0 +-0.1038734156433597 -0.1167419194667879 0 +-0.1179251954197863 -0.1810105539615855 0 +0.01047019022377623 -0.1907488825630235 0 +-0.09436576560684246 -0.1421370356605365 0 +0.1245734789907178 -0.1246873939860032 0 +-0.1525000000000001 -0.1027653137062202 0 +-0.1525000000000001 -0.1972346862937802 0 +-0.007800158505466238 -0.1288465128017197 0 +-0.1454021225699972 -0.1900762708288294 0 +0.1005515267308444 -0.17862351227387 0 +0.08167879726794562 -0.1871743976851261 0 +-0.1434101813750472 -0.1396803019583653 0 +0.05887560420852672 -0.1090004060054226 0 +0.1418870163072439 -0.1783217633714643 0 +0.001812922546455956 -0.1665200344957163 0 +-0.1452745928561265 -0.110287145546467 0 +-0.07839988917857257 -0.158360982249185 0 +0.04266680849232119 -0.1330968333477005 0 +-0.06538935030662493 -0.1624025107732362 0 +0.1242339037869745 -0.1760207027797766 0 +-0.07376546803579472 -0.1692894379066223 0 +0.01549206319504042 -0.1560373212715914 0 +-0.1241928699694442 -0.1357956350085913 0 +-0.07934383760860725 -0.1486287718014112 0 +0.04749378008011321 -0.1029779568483162 0 +0.1070871602348823 -0.1897641045819363 0 +-0.03388695471768938 -0.1263881361810944 0 +-0.01112330515834802 -0.1487779324284288 0 +-0.07467175516182555 -0.125873140432291 0 +0.04699098626918515 -0.1471629558073809 0 +-0.02838342908425712 -0.1733647854827733 0 +-0.1159988764168523 -0.1448583040332828 0 +0.04606731777958721 -0.1397211067041354 0 +0.09641071897688208 -0.1187948549849871 0 +-0.07572309706907812 -0.1466374991088392 0 +0.1076840278200672 -0.1794419343699425 0 +-0.143089832635818 -0.1603121640382739 0 +0.03745987192097792 -0.1093465252350351 0 +0.06478103500661121 -0.1465246766403986 0 +0.0364873761952875 -0.1642998124212064 0 +0.03562570285045367 -0.1680636117678092 0 +0.04382547294024868 -0.165833298527366 0 +0.05613652158365089 -0.1853692766200025 0 +0.1571262737030106 -0.152311296976964 0 +-0.01175807802721118 -0.1656817485519271 0 +-0.05156885988793665 -0.1159781690805173 0 +0.04223384137608755 -0.1293143398286983 0 +-0.1221238507968729 -0.1137612783422698 0 +0.1393800736598691 -0.144776096171384 0 +-0.1173629197067544 -0.1619063114838598 0 +0.1470538366803863 -0.1787259595218309 0 +0.1567399593854329 -0.1232904344788233 0 +-0.1523585173324523 -0.146246784821378 0 +0.09140366572237113 -0.1967937224448674 0 +-0.1183432967233425 -0.1188800858477257 0 +-0.08905164466533345 -0.1857567943003967 0 +0.1568266335415528 -0.1924922268526942 0 +0.1179540380947956 -0.1213902719818907 0 +0.07837070972262673 -0.1126172672934183 0 +0.01386445051627107 -0.1229606577409569 0 +-0.1403208532799781 -0.190863546658199 0 +-0.04290790882020021 -0.1618658923851939 0 +-0.1276671426802194 -0.1893872079571352 0 +0.0001192265508319844 -0.1080985784839727 0 +0.1383233716677547 -0.1606227573842379 0 +0.1344603910730718 -0.1927745501480669 0 +0.08634741875636756 -0.1924887246614961 0 +-0.1001601885645066 -0.1581732170364994 0 +0.05243818941174253 -0.156757630137737 0 +0.1241692492638096 -0.1842315480554355 0 +-0.05749999999999999 -0.1973329533334307 0 +-0.15226918370625 -0.1724938198988681 0 +0.08745123405126488 -0.1283897151657848 0 +-0.08824192076794878 -0.1159716996125736 0 +-0.02298583860918122 -0.1344675973872022 0 +-0.02132479743480209 -0.1782932509458727 0 +0.0103197128070353 -0.1323059078053062 0 +0.1568638593388106 -0.1081319108099246 0 +-0.1281464535898769 -0.147133459979475 0 +0.03265158692254532 -0.1827361989929266 0 +-0.02390269456043696 -0.103400846019619 0 +-0.1347873396266213 -0.1872934099587524 0 +-0.1275945398445608 -0.110374351920836 0 +-0.01936191315642098 -0.1190258520274819 0 +-0.09927863439586343 -0.1846333855310179 0 +0.1570168428085205 -0.1726158443748621 0 +-0.08561876549902134 -0.1254437757096817 0 +0.06587450544667965 -0.1915036473888697 0 +0.02189035443078837 -0.1765135929677066 0 +-0.02869264806524161 -0.1094076743576951 0 +-0.0584224375306012 -0.1509454648497747 0 +-0.06797289788980584 -0.183874846424798 0 +-0.07092795746184198 -0.1860082485403893 0 +-0.04557086947467914 -0.1875284509715324 0 +-0.05750000000000004 -0.1026391081654581 0 +0.05213891124552544 -0.1839712443841935 0 +-0.09516333300093374 -0.1481052399741767 0 +0.1280967822883702 -0.1438456056428221 0 +0.04832910640461972 -0.1905777886965432 0 +0.05339834874693097 -0.1499784913153031 0 +-0.03124556407713337 -0.1626658625974406 0 +-0.08376615228330975 -0.1635043169700083 0 +-0.06830713710364619 -0.1531435755008191 0 +-0.115283169727571 -0.1775706357833617 0 +-0.06749999999999996 -0.1973788771778344 0 +0.1408134841071537 -0.1930043692910351 0 +-0.1527739723447658 -0.1269058676861665 0 +-0.02085138158993218 -0.1516932059761183 0 +0.0901977756771235 -0.1618172880792911 0 +-0.06525814247534109 -0.1512005974103851 0 +0.06904406188108821 -0.1615795467206377 0 +-0.07890439070881733 -0.1093048050958754 0 +-0.0749201001271769 -0.1347400464225406 0 +-0.02224294468055232 -0.1693300810047673 0 +-0.01749999999999996 -0.1973958441634144 0 +0.1241680811585437 -0.1086298856883009 0 +0.1526252951949818 -0.1414151904983769 0 +-0.0661477045063644 -0.190660151942958 0 +0.1337822436462277 -0.1082787037591434 0 +0.1102014016230762 -0.1911599835329989 0 +-0.006366786277471903 -0.1359628903025343 0 +0.04593257834762502 -0.1270864959051788 0 +-0.0685200804556053 -0.1246010383096468 0 +-0.0662403759295996 -0.1268369232431533 0 +-0.1053418726995019 -0.1524721078510178 0 +0.03629744492247119 -0.1032061867779127 0 +-0.005324361992329267 -0.1325154800417776 0 +-0.0539091099734621 -0.1084868498506447 0 +0.1352997163595332 -0.181114870516107 0 +-0.07794943217756918 -0.136883384104779 0 +-0.04190264282751804 -0.1765682770587364 0 +-0.07173554255134013 -0.15902071765201 0 +-0.07259251200373179 -0.1624368132500667 0 +-0.1236982441344992 -0.1639433939744114 0 +0.04657566586462023 -0.1176299799843963 0 +-0.1217879948642954 -0.1561083654401419 0 +-0.07750000000000003 -0.1025774864158085 0 +-0.0359272809422365 -0.1910831278882839 0 +0.1222231054225593 -0.1028339453779156 0 +-0.07246131715164977 -0.1521732681400686 0 +-0.08031045923890687 -0.1794294539283015 0 +-0.01487171786939866 -0.1288274575498229 0 +0.1443472860195836 -0.1848336966494241 0 +0.03615038131325098 -0.1900488403205463 0 +0.1174448399311739 -0.1322643464115985 0 +-0.1278577081662317 -0.1733412383756375 0 +0.07119187614490571 -0.148865420115609 0 +0.0744052770711378 -0.1497440492272588 0 +-0.1525420306237631 -0.1904222618234945 0 +-0.1525438391173501 -0.1095758621199168 0 +-0.1367789945626892 -0.1809103189628627 0 +0.1315910582547332 -0.1332457888998973 0 +0.02257318828241114 -0.1574786752047454 0 +-0.05988430098015077 -0.1161830585157749 0 +-0.05397600775291665 -0.1359437252203325 0 +0.01675654940290671 -0.1926936697326537 0 +-0.1197650616254087 -0.1651519687331602 0 +-0.08847118605654936 -0.1774702308130574 0 +0.07276502928302983 -0.1762664545303417 0 +0.1202790321487795 -0.1268535309807602 0 +-0.04316568276353248 -0.1688173991941219 0 +-0.1240831364782344 -0.1602572591459026 0 +-0.1424054142487655 -0.1315439466069549 0 +0.07443995020227509 -0.1184886258870319 0 +-0.08469477549648521 -0.1665765914875809 0 +-0.07644173781629601 -0.1908496931473057 0 +-0.1115473295743716 -0.1518929030056414 0 +0.08809013977786308 -0.1068988522591761 0 +-0.06749716527945621 -0.1026113894532021 0 +-0.1420006087118485 -0.1511232737219025 0 +0.1069165819501802 -0.1270999081739796 0 +-0.07376615718042875 -0.1733668724118593 0 +0.09016984375514921 -0.1893302716814527 0 +-0.1158519241168172 -0.1304140743860217 0 +-0.1045023004784223 -0.1302592434252762 0 +-0.02696093519150079 -0.1172166300839176 0 +-0.03321335564660811 -0.1812081400353905 0 +-0.02799004775356843 -0.154392684734203 0 +0.03946302399663205 -0.1469842235596224 0 +-0.1514568852460244 -0.1662532937388792 0 +-0.09541274285011454 -0.1586420170359906 0 +-0.03504677867107325 -0.1733029957666794 0 +0.07088331346655377 -0.1084695183215705 0 +-0.03977219140891049 -0.1896235103223286 0 +-0.03273004892100612 -0.1187500734756906 0 +-0.07267963634914128 -0.1191189948534753 0 +0.09959205817605835 -0.1347427088148963 0 +0.07767638873817567 -0.1972516154529624 0 +-0.07960476675923146 0.008133836127609449 0 +-0.1036556603773585 -0.0436556603773585 0 +-0.05206694982702022 -0.03646425849792045 0 +-0.109706612673334 0.04903038746912314 0 +-0.05086796030785739 0.04827164008452077 0 +-0.119923020982446 -0.004999419488180705 0 +-0.0400345988851122 0.001906300392166016 0 +-0.07434712644816491 -0.06433182740948984 0 +-0.03394118473443956 -0.06516054232206675 0 +-0.08019548563245675 0.06627548655243293 0 +-0.1266511130125918 -0.0672877796772126 0 +-0.12926248101617 0.02491114463398994 0 +-0.08017866743052302 -0.02353118839109906 0 +-0.1297028204103413 0.07084251066350267 0 +-0.02960413852383762 0.07007260329536033 0 +-0.08281030912728064 0.03744270656917888 0 +-0.1307547972639982 -0.03240041109185157 0 +-0.02927898017003876 0.02900594604153785 0 +-0.02806324744313969 -0.02316817994414566 0 +-0.100523867459716 -0.07284633146558543 0 +-0.05775876902594226 0.02293343464732219 0 +-0.1034787024231198 0.02044193432409456 0 +-0.1043300759710853 0.07435425076319217 0 +-0.05566992402891473 0.07435425076319219 0 +-0.1363401392785843 0.04706126678600423 0 +-0.06187444313466942 -0.008390351223525274 0 +-0.05442222347387625 -0.07674582916987527 0 +-0.02328851758968927 -0.04549750173885091 0 +-0.09590849449432767 -0.007647431880983762 0 +-0.02209315031400733 0.0492341351800609 0 +-0.1383139358189196 0.003813450708468393 0 +-0.08315863180834439 -0.0448654946301122 0 +-0.02077083409876114 0.009854445892158647 0 +-0.1092885364910232 -0.02319666330043406 0 +-0.1407824877146289 -0.05097980314776832 0 +-0.05575945046642058 -0.05633349249291366 0 +-0.01974887317043955 -0.07907900035759913 0 +-0.1392087660660474 -0.01552336091476316 0 +-0.1407535224115282 -0.0802172749233858 0 +-0.08485529535886278 -0.08250279245399689 0 +-0.04497482432575961 -0.01815576909432325 0 +-0.06990087751628116 0.05041178802573295 0 +-0.1213218837396491 -0.04982808438837059 0 +-0.1162609306029776 -0.08177911976095023 0 +-0.01749042989392636 -0.008092918647119845 0 +-0.09224468808433031 0.05180144122581277 0 +-0.0882796088069782 0.08209510330873773 0 +-0.1426211581668007 0.08262115816680063 0 +-0.01737884183319938 0.08262115816680064 0 +-0.03860212958573214 -0.08262379173955062 0 +-0.01724161303625134 -0.06210723579952972 0 +-0.04064782701315547 -0.04958368554378047 0 +-0.07137913711237774 0.08312962407395494 0 +-0.117034761055759 0.0117807410936849 0 +-0.04095493233691837 0.08321766478445916 0 +-0.11893011893293 0.08282083420859047 0 +-0.09431002292315327 -0.05704833999240892 0 +-0.1131075965817957 0.03175739651039699 0 +-0.1443510579505303 0.03156046154943314 0 +-0.06849883758988286 -0.03569337317197874 0 +-0.04161615682265341 0.01823663524535606 0 +-0.07451770017726025 0.02272279761170072 0 +-0.1435928318627192 0.0600251357659415 0 +-0.06448508307358876 0.008278140780169356 0 +-0.04508403422049386 0.03475338863138806 0 +-0.09451181854033487 -0.03044645943398622 0 +-0.09889371824372374 0.03656264653227154 0 +-0.1156850202746324 0.0636420574474712 0 +-0.04448531446850963 0.06337935179670665 0 +-0.1095903130143544 -0.05951958250807693 0 +-0.0777731095045089 -0.007958524469181771 0 +-0.01547510698891377 0.0641504299529809 0 +-0.1449172877985799 -0.06539612421041506 0 +-0.06803640750527054 -0.08460037263828221 0 +-0.01565401571972867 -0.03176943193878049 0 +-0.01491696808285821 0.03593999791347259 0 +-0.06041690588928431 0.03827285371450938 0 +-0.09524306130706361 0.007087644638071112 0 +-0.1450937631163013 -0.03689108627853409 0 +-0.06038155387610268 -0.02293963673295053 0 +-0.03745639285421637 -0.0351926534465051 0 +-0.03654168310057957 0.04598533193140275 0 +-0.1238222533867998 -0.01895138534677657 0 +-0.1452911820586857 0.0174120567932225 0 +-0.06886657292422878 -0.04998914585274059 0 +-0.08851480889652343 0.02364278394072939 0 +-0.06645359820408023 0.06466915839529391 0 +-0.1168615684317702 -0.03578449373300179 0 +-0.0324260833899046 -0.009710937325531145 0 +-0.1224148356696493 0.04420035396537707 0 +-0.09633847577932954 -0.08611005476217698 0 +-0.0141498379094382 0.02279980261689771 0 +-0.102210653224292 0.0609400543911424 0 +-0.1083819420344423 0.002467675565140036 0 +-0.1288258489601159 -0.08641370040164024 0 +-0.1281449356746443 0.05726726774082286 0 +-0.1005462393402339 0.08599468414781591 0 +-0.08688412395782565 -0.06848743252345764 0 +-0.05779396853428218 0.08622053827426719 0 +-0.05106660620623873 0.00943956672086637 0 +-0.04721901317190215 -0.06619189966968948 0 +-0.09259858850251346 0.06923270447985402 0 +-0.01301620159269193 -0.01891155787524273 0 +-0.1472193615157086 -0.004254413891700858 0 +-0.1310280985181846 0.08777918923417365 0 +-0.02894169196664303 0.08770108291080464 0 +-0.1312335086379748 -0.005855780142616101 0 +-0.04945166865839441 -0.00645548373739021 0 +-0.0312259700660799 0.05776755138652922 0 +-0.06226969060843019 -0.06763315646883911 0 +-0.1472490975745247 -0.02539073524460089 0 +-0.1077600039318437 -0.01236017973812385 0 +-0.04952322166386355 -0.08752219089819113 0 +-0.1464404013632998 0.04335932396527237 0 +-0.01258737628813402 -0.0508463851608737 0 +-0.0912525142031563 -0.01873491315804015 0 +-0.1311843729387418 0.03613134865967983 0 +-0.01208849613769141 0.002482737943199919 0 +-0.1150946009997873 -0.0699552527278744 0 +-0.1283442449348172 0.01185249798474514 0 +-0.1482057422576232 0.07281863501380077 0 +-0.01252032206230901 -0.08791034499727873 0 +-0.03261285566021376 0.01093415798955957 0 +-0.02819137138108086 -0.08840335381512061 0 +-0.01346174542353611 -0.07209606289958385 0 +-0.02963500394430911 -0.05491814921392718 0 +-0.07108868122500536 -0.01813245334977712 0 +-0.05554530910978435 0.06022819780271402 0 +-0.08057466018245289 0.04834247979466476 0 +-0.08639738530769693 -0.002712690584354574 0 +-0.08242775838830188 -0.05560921318694703 0 +-0.1073653167437593 -0.0884579720798381 0 +-0.1487166006598883 -0.08880241010035939 0 +-0.01180794431468529 0.05345245870121232 0 +-0.130793663211794 -0.04325176909081854 0 +-0.02746371586629538 0.0008853695012071026 0 +-0.07161894236125481 0.03381140031346263 0 +-0.05865805656337532 -0.04549094769792109 0 +-0.02634913613610618 -0.0355121341914011 0 +-0.149065056644497 0.006957868115860957 0 +-0.1302746565669141 -0.05651188308067036 0 +-0.02858767391953663 0.04032710781410936 0 +-0.1136791880433637 0.02268842768310052 0 +-0.08421154964587579 -0.03352741044090388 0 +-0.09176126981370276 -0.04163636696604982 0 +-0.07348008258829455 -0.07521298859392367 0 +-0.07967077047342322 0.08924233472096313 0 +-0.009138932634322397 0.0741494121443627 0 +-0.03026579297518974 -0.07547226898391374 0 +-0.1493075497514353 -0.05563080779220712 0 +-0.06967317408822972 -0.000911425394547339 0 +-0.1105112026777533 0.08937207494933122 0 +-0.149469993262072 -0.07487775213502951 0 +-0.07782535934317601 -0.09011469739826009 0 +-0.02386860092263488 0.01979900186281139 0 +-0.1252445822921397 0.002550368156193117 0 +-0.1052058482186365 -0.03341178133934795 0 +-0.07919821296581771 0.07794063675018026 0 +-0.1304409359512607 -0.0757350724427981 0 +-0.1191133003247503 -0.05840447950345302 0 +-0.120264006557829 0.07280391103833193 0 +-0.04557787356497153 0.0736758037989404 0 +-0.04777184851842814 0.09033502692455453 0 +-0.009931172365039737 0.01170942397668705 0 +-0.1337196646651736 -0.02224869131821995 0 +-0.05731169773270849 1.279624615013221e-06 0 +-0.01025264007110738 -0.04080634517318461 0 +-0.1501335681674258 0.0902379362822385 0 +-0.01017963339621346 0.08982036660378662 0 +-0.05972840565630969 -0.08940932366357829 0 +-0.1499984997072986 0.0533311876392937 0 +-0.04557638004287328 -0.02884211598986886 0 +-0.1501262284593851 -0.04572864202178245 0 +-0.118364897946286 0.05343770000696203 0 +-0.1501463756247123 -0.01353526751688983 0 +-0.08760183018592041 -0.09051987373026521 0 +-0.1374789181080218 -0.09025518818373361 0 +-0.06531383740465263 0.07404406609886238 0 +-0.0870650115490318 0.01344005637418466 0 +-0.112029149817338 -0.05012666416601807 0 +-0.1019652626636947 -0.01877566779524481 0 +-0.1076774398251451 0.01164726878102104 0 +-0.09127503995052506 0.04315809643345181 0 +-0.100051960781771 0.04589952919557309 0 +-0.0093401955954786 0.0440497808505786 0 +-0.03579586704499105 -0.01820384966776725 0 +-0.03269091846434742 -0.04385190837650834 0 +-0.07177620739266147 0.0127607140872428 0 +-0.04104333117286785 -0.05990836601246261 0 +-0.02032794079221763 0.07336739149383317 0 +-0.06051135316790737 0.04749630944053228 0 +-0.04241018233134457 0.05395696485846082 0 +-0.07680535942734375 0.05705748143371684 0 +-0.04119514366687749 -0.07335460338416358 0 +-0.02270115651238044 -0.07035753381932987 0 +-0.1387791323575888 0.02380405872578074 0 +-0.1048527000543585 0.02986281354697691 0 +-0.05505402199055483 -0.01490479931784085 0 +-0.04810975787593432 0.02534307621223159 0 +-0.05017691138365465 -0.04813699178235003 0 +-0.102382838773601 -0.05311217545965345 0 +-0.1513234654093569 0.02571818716888679 0 +-0.09216086409862036 -0.07755541494609029 0 +-0.1390118537368208 0.07382717609822027 0 +-0.1207768735834226 -0.09139492544698444 0 +-0.1073913329279233 -0.07933312339446263 0 +-0.1073626660708035 0.0399303379150345 0 +-0.08791754785955497 0.06110505794687335 0 +-0.09213080180390375 0.09158590903654358 0 +-0.03878175910998057 0.02724201209191079 0 +-0.06463503378360136 -0.07570034254748388 0 +-0.07132932718152814 -0.02644959125265382 0 +-0.100839987008795 -0.06375155305946167 0 +-0.05206476513066353 0.03991706271146012 0 +-0.1394020097736969 -0.02931484171413527 0 +-0.00923453506890329 -0.0109944126156913 0 +-0.08640792693976983 -0.01081171662668299 0 +-0.03558431649163413 0.0362209912196009 0 +-0.04096119737162765 -0.01073305995426907 0 +-0.06653911200449958 0.09126221292526805 0 +-0.1266683772267952 0.07916401829194547 0 +-0.03270064959076129 0.07935724990708207 0 +-0.021429641473266 -0.01626519206700043 0 +-0.06672036710767429 -0.059102889724898 0 +-0.1231227728886268 0.03186032323371568 0 +-0.1355480632632826 -0.06322754313412665 0 +-0.09050913357182516 0.03259277698130932 0 +-0.04410107499983779 -0.04085505921147222 0 +-0.06002305061405935 -0.03259505303597603 0 +-0.1228712883645619 -0.02897312113944481 0 +-0.06591380954926063 0.02692278916839211 0 +-0.07398056611575311 0.04292959998037676 0 +-0.1400290025086903 0.09088322312257013 0 +-0.01995716685499658 0.09080008481224178 0 +-0.123010002396107 0.0910278278919989 0 +-0.03695222538026625 0.09101912737927362 0 +-0.1361672772614855 0.0567185719335876 0 +-0.020408016002024 0.02821380909520652 0 +-0.09606704798848471 0.07745310639562539 0 +-0.009083560736668665 0.02909295249493205 0 +-0.04125519557324591 -0.09114107680919301 0 +-0.05556837251952496 0.03175838550242047 0 +-0.03267489644736558 0.02063248001463314 0 +-0.008846279974265287 -0.05916405482075597 0 +-0.07378672403007956 -0.0426037979540077 0 +-0.1223663012774292 -0.07536546154216087 0 +-0.02349847322181684 0.06381841508738265 0 +-0.06400228849784514 0.01678065834827933 0 +-0.1102735976879196 0.0802463862541255 0 +-0.0809469439217204 0.02816315247635374 0 +-0.1520817342164817 0.08034373630963049 0 +-0.1155887025691339 -0.01791655019838235 0 +-0.04965234477086811 0.08089320635790045 0 +-0.08981037312251318 -0.04935101147308751 0 +-0.02103990788638139 -0.05484552881808821 0 +-0.02607283056994399 -0.06203578759299964 0 +-0.02028080750531663 -0.09130607808758689 0 +-0.1375191774111998 -0.07188168806129196 0 +-0.1165537963801007 0.002290396846458841 0 +-0.04636945887536213 -0.07901925154656136 0 +-0.1380250982041448 0.0135562992716035 0 +-0.1224348883813111 0.01836410750470368 0 +-0.1519851051179679 0.03526347465629674 0 +-0.06297161897430997 0.05619749153798422 0 +-0.008412426232012143 -0.0269714646768813 0 +-0.00843505745724861 -0.07998357581641527 0 +-0.09676946134940491 0.02639379779852933 0 +-0.1309515045709733 -0.01385568765729795 0 +-0.04435811927169194 0.04359866647684749 0 +-0.01948795714300038 -0.02479489790368434 0 +-0.07977278075240368 0.01670041299669612 0 +-0.1079109106223799 0.06682065827372341 0 +-0.1099006936607104 0.05755462544588513 0 +-0.09893140849317597 -0.0001937892748666527 0 +-0.03815935802256189 0.06943423650620162 0 +-0.1518669494430251 0.06472222683558131 0 +-0.04261567128497978 0.01013509373145647 0 +-0.1386537023472609 0.0393565771610959 0 +-0.09654688666357558 0.01487343169466073 0 +-0.1518778395518617 -0.03199832593318504 0 +-0.008146338312197188 0.08174184236775282 0 +-0.0505811239602966 0.01682576803252333 0 +-0.07302295256076956 0.07110672981270799 0 +-0.1397762535721682 -0.04319223859587442 0 +-0.136046848081923 0.06478626360821131 0 +-0.1241980777122893 0.06466788775327195 0 +-0.1077115128447583 -0.06796998218064423 0 +-0.05083475100450564 0.06696240680671399 0 +-0.03522821177454169 -0.02639618099313388 0 +-0.1242532935990795 -0.03717232571568285 0 +-0.05227939313194524 -0.02387464803280861 0 +-0.1395404536853043 -0.006853788226919628 0 +-0.04880233805646816 0.001879758509959595 0 +-0.1119241047040088 -0.04246819827620661 0 +-0.08816150134096645 -0.0262667923793235 0 +-0.007859078865416251 0.06089153452800799 0 +-0.02002080815895747 0.0005612332772129782 0 +-0.07626465003520641 -0.0328187713628082 0 +-0.1525423400108954 -0.0672633156489332 0 +-0.07431938519922091 -0.05581465081403887 0 +-0.1285546305233959 0.04930479375927323 0 +-0.02472669008876541 0.07997539554188199 0 +-0.07756693792224972 -5.780308314641102e-05 0 +-0.06958445845681331 -0.00883178860303567 0 +-0.08003363071769824 -0.01553461304617445 0 +-0.06760891437679695 -0.09233117616828794 0 +-0.05490155032931862 -0.06468483667185276 0 +-0.1351136547711946 0.08068018976457417 0 +-0.01791331949950388 -0.03948575950685006 0 +-0.1147378339953168 0.04374295542745554 0 +-0.06602605042978363 -0.04280171658272025 0 +-0.01897428000991275 0.05670956688778768 0 +-0.01806872517746904 0.04321864395663889 0 +-0.1413944339221811 -0.05844285096429323 0 +-0.1123897841858871 0.07288362047084392 0 +-0.02961304824462409 0.05032829305145144 0 +-0.1526814630187794 -0.08202731756392363 0 +-0.1013915343206488 -0.02629708666965907 0 +-0.08679379263537429 0.07457459283907426 0 +-0.15217260158481 0.01361880089168997 0 +-0.1424132004748259 0.05174582808871784 0 +-0.06254974135005689 -0.01562702645960299 0 +-0.123276298941743 -0.01186264515612606 0 +-0.08760965265451268 0.006093443989766306 0 +-0.1118296957002049 -0.004334081774412753 0 +-0.1001735043276675 -0.09196657198777705 0 +-0.09422913877132261 -0.06807253231949545 0 +-0.0997534026783955 0.06787699328566932 0 +-0.05777134242969509 0.01246955829480237 0 +-0.07945877880446291 -0.06999509457972526 0 +-0.04827728733920762 -0.05833508456945394 0 +-0.09725246466439891 -0.04735182993115139 0 +-0.05900685593353009 0.06756963987226654 0 +-0.06039306239820189 -0.08189010664765933 0 +-0.007208524244091142 -0.003663683883061482 0 +-0.06362559026298559 0.08128190930205706 0 +-0.1026217498161122 0.05346013934144499 0 +-0.00745330812970804 0.03676136068296176 0 +-0.02518332453339319 -0.006198101562246337 0 +-0.07567858479723941 -0.08205041291403044 0 +-0.0341355638090397 -0.002388476713924515 0 +-0.09500206401617076 0.05890101651707211 0 +-0.07248957110859312 0.005696832926264004 0 +-0.06673974582133015 0.04186665941792653 0 +-0.06936174082937982 -0.06945322809033963 0 +-0.1148464126271229 -0.0289952026674898 0 +-0.06198815210647369 -0.05213479478711146 0 +-0.08399738948482141 0.05477952170917488 0 +-0.07316678037606709 0.06346367059963 0 +-0.03381149844529423 -0.09288790869799887 0 +-0.1518356604331797 0.0008054246128383855 0 +-0.08744332398997826 -0.06118777896338485 0 +-0.007046392606940533 -0.03439556601519246 0 +-0.1408008707449056 -0.02221328902854597 0 +-0.1362200141233986 0.03085477622423565 0 +-0.1038353946605736 -0.005840421230694134 0 +-0.007528574905112396 -0.06618330388104381 0 +-0.1524189368274534 -0.03896732491746959 0 +-0.11311784784254 -0.09318998020192855 0 +-0.007149080343057851 0.01916069267117857 0 +-0.0370287483743284 0.06232605401851066 0 +-0.09843935631279616 -0.03655032470120173 0 +-0.0767336097802411 -0.04887992934745661 0 +-0.1023236598069898 0.00672035739345042 0 +-0.09980801024884423 -0.07976505083432292 0 +-0.02847819207560233 -0.01576395582168295 0 +-0.119279202215465 0.03784309809009036 0 +-0.1328523971799509 0.01867138396738505 0 +-0.1043582011058759 0.09287184925740075 0 +-0.07375903573647276 0.09297601295259804 0 +-0.006924408517890512 0.06757293166297754 0 +-0.1185604886685599 -0.04283241450869552 0 +-0.0492473502105135 0.05683755979239209 0 +-0.01637059583878179 0.01563179486562527 0 +-0.1316620243077301 -0.09281015956152863 0 +-0.1197851516838928 0.02564596441588201 0 +-0.1367600340278451 -0.03634904706273973 0 +-0.1533955229876789 -0.007668769864680668 0 +-0.1529768355456853 -0.02022323783522281 0 +-0.02236412992794577 0.03501735556071886 0 +-0.1233346861458286 -0.08247134466926477 0 +-0.05528902625441597 0.09344502873683211 0 +-0.1323560011962777 0.0009132044537556638 0 +-0.0069700619907572 -0.09307789631990218 0 +-0.09372381774119545 -0.09301715313279953 0 +-0.04867916074931035 -0.0722621389459998 0 +-0.08536722117415807 0.09309098103348622 0 +-0.05597921793898864 0.05317707941058473 0 +-0.1535177421745935 0.04738705993861502 0 +-0.06968274324038491 0.05807800719601151 0 +-0.006973070127551046 -0.04660248835065711 0 +-0.1432494502893333 0.06789181243927811 0 +-0.03158180052208458 -0.082710891751517 0 +-0.06052631484240599 -0.03792331504096452 0 +-0.05373631575351288 -0.09346886021927953 0 +-0.1444312465255849 0.002436415415068309 0 +-0.03922941026376624 0.07717573583989364 0 +-0.08955425074784469 -0.0838626082964516 0 +-0.006771422006384387 -0.01782057796803856 0 +-0.04176275232234786 -0.02277839691290283 0 +-0.133322341712461 -0.08342839831801882 0 +-0.116248302403765 0.09332710892578751 0 +-0.1310331379488902 0.04276253020636077 0 +-0.1329132233729657 -0.05002930804626676 0 +-0.02643504816679633 0.01480775459599656 0 +-0.006825303303552427 0.007063225012782863 0 +-0.03405892014925944 0.004427529643328661 0 +-0.1031697820349272 0.08198784640607748 0 +-0.1531559470629108 -0.09392216569210438 0 +-0.08149706851347012 -0.06353892349036917 0 +-0.1441884969547151 -0.09387666840608527 0 +-0.04433517909348889 -0.004572885528013331 0 +-0.02869104536150152 -0.06922422361844005 0 +-0.06301728387819779 -0.00150318555016565 0 +-0.1130542434402003 -0.07587248798642963 0 +-0.1322047341949589 0.09340655947721022 0 +-0.02779976825873336 0.09338691724137732 0 +-0.07950974135581433 -0.03896965460041808 0 +-0.1234954261786197 0.009071236660894929 0 +-0.08704942627904667 -0.07460403442994726 0 +-0.05203022406172899 -0.04279340427054192 0 +-0.09678287460215008 0.09348087685699709 0 +-0.03577654838201015 0.05312491129916116 0 +-0.1534651216806834 -0.06086810791098263 0 +-0.1422714688863068 0.009968376197182762 0 +-0.09464514001159692 0.08430275072601469 0 +-0.08190153422062456 0.08271656475230556 0 +-0.01615053304479988 -0.04642798741437543 0 +-0.03372842198925197 -0.04881676406881558 0 +-0.1147044320740955 -0.01072318107211669 0 +-0.09427953329899631 0.001884897818639203 0 +-0.04338781045577622 0.09364781788788454 0 +-0.1243496297722178 -0.00310423418826414 0 +-0.118027944031691 -0.02297650734826661 0 +-0.1158956775219911 -0.05428917730819806 0 +-0.05725695758784533 -0.06917642714186066 0 +-0.06551455318230792 -0.02778308305626192 0 +-0.05674751929123813 0.08048081599045015 0 +-0.04177914155328463 -0.06509706954890673 0 +-0.09587657926270249 -0.0144372480127544 0 +-0.05431126364154561 -0.02983917848522738 0 +-0.09551340221216187 -0.02358263243230808 0 +-0.06093053007628601 -0.06054819606339478 0 +-0.04528449228142009 -0.05399282013881366 0 +-0.15360991895684 -0.05110386034618286 0 +-0.02687942771283008 0.006216456194733735 0 +-0.04650851858996422 -0.09396367040107331 0 +-0.02924414274513022 -0.02899720047785315 0 +-0.01459044921790433 0.008430267478802971 0 +-0.05544722389236655 -0.00548304662844709 0 +-0.08605218583979263 0.06737713645772436 0 +-0.09082749381951583 -0.03506115026973024 0 +-0.01466041460937331 -0.01302992085275149 0 +-0.1138603898556325 -0.06329767755122216 0 +-0.121451340632507 -0.06672406140495163 0 +-0.1321907598505323 -0.07050072985971637 0 +-0.02716117515534509 0.05511504716329896 0 +-0.007066100585811828 0.04872738950507277 0 +-0.006118947244198515 -0.05391250719449089 0 +-0.06157360389389223 0.0304994340583376 0 +-0.1538319776345921 0.05907779295433075 0 +-0.03356936772595684 -0.05857127435922266 0 +-0.04922668918800264 -0.01297299030955886 0 +-0.08201688543768323 -0.0946689010418397 0 +-0.1086242248580222 0.01807194912867902 0 +-0.1109056063750923 -0.03563031432630326 0 +-0.1109578826124196 0.007227573678152419 0 +-0.1536141249507637 0.02030846517446587 0 +-0.125944785846183 0.08567039422025198 0 +-0.03477501749045971 0.08509817081419913 0 +-0.0612150309141342 0.09378116717605196 0 +-0.110745329004316 0.0262235280598729 0 +-0.1284238306282723 -0.02651371515004155 0 +-0.1072728423699752 -0.01798161695825513 0 +-0.144935778858347 -0.01015035786736539 0 +-0.1459348854619615 -0.01886542757035846 0 +-0.05316947158084335 -0.08402949069921602 0 +-0.1450276636304063 0.09350760522709436 0 +-0.01495431302306174 0.09334656241111201 0 +-0.1250310847893885 0.03990539896622118 0 +-0.08499292911594696 -0.01941388761406413 0 +-0.1438334175996703 0.02556842736257417 0 +-0.1453958462899229 -0.0507627019011753 0 +-0.1013412261250302 -0.01206025923858663 0 +-0.01441733246712503 -0.08264414162558778 0 +-0.120401453274903 0.05785794377382995 0 +-0.08352729434920927 0.04202031100518622 0 +-0.02116923389002787 -0.03096869803658404 0 +-0.03138481053928185 0.06451843636457048 0 +-0.1251949372394686 -0.0937459798014223 0 +-0.1246753001557876 -0.05370440909563853 0 +-0.02262838764324112 -0.08590020042724697 0 +-0.0867685004340477 -0.04010117560895565 0 +-0.1301510813060469 0.06260613206542659 0 +-0.14598043737319 -0.03098971832604409 0 +-0.1539674105825377 0.04074936914005042 0 +-0.04629348343369764 -0.0352495758426876 0 +-0.1261034870441647 -0.04448887341110865 0 +-0.1444520163090885 -0.08692477886157386 0 +-0.01738501106825553 -0.07581144629261335 0 +-0.01560904858086616 -0.0669771680353419 0 +-0.01501521497585968 0.05004039031614927 0 +-0.1318734265202308 0.007982912807290164 0 +-0.08262949039602401 0.02118181528150771 0 +-0.01434249742069975 -0.09386888740961595 0 +-0.1005466196138597 0.01292377323737285 0 +-0.01411364133703505 -0.004405506402074182 0 +-0.1261215175944866 -0.06080952206396927 0 +-0.1411334167719465 0.04437987299846455 0 +-0.1450335777425417 0.03776079097056155 0 +-0.01552468028246562 -0.05530742103412727 0 +-0.1525755822711524 0.07416476305986125 0 +-0.006026584835476387 -0.08552124911407334 0 +-0.04380876826112581 -0.0859803267929027 0 +-0.02539970012017444 -0.09368260484429147 0 +-0.1547231639906942 -0.02592990329383905 0 +-0.08643205644008189 0.04871320799796144 0 +-0.06706773693608509 -0.02122294281951898 0 +-0.07359433061490374 0.07703733490878793 0 +-0.09060586845738819 -0.006423625252845025 0 +-0.1443121947195665 0.07678943541974416 0 +-0.1282730372111965 0.02948706943700197 0 +-0.1348614732267283 -0.0556791400166493 0 +-0.1033785936027079 -0.08589787317518208 0 +-0.112745498760207 -0.08629202029630759 0 +-0.01521870419313904 0.06923216459234018 0 +-0.006049012642082891 -0.0747447009777526 0 +-0.07998010878909076 -0.07523223310475684 0 +-0.1462709921524658 -0.07975570072288646 0 +-0.06727472047766365 0.02134814721213611 0 +-0.03573617692792609 -0.07722168718665877 0 +-0.07250137148199277 -0.09482072994572444 0 +-0.09365853607551357 0.02214163581477952 0 +-0.07679502587215005 0.03312689088877571 0 +-0.03193309215386541 -0.03631008912213644 0 +-0.02655191763920271 -0.04082786041395342 0 +-0.03922997602406273 -0.04023829993023022 0 +-0.07555735473460978 0.05117567765220951 0 +-0.1540671037678548 0.0940671037678547 0 +-0.005932896232145295 0.09406710376785472 0 +-0.03860964461237679 0.04094456397487199 0 +-0.03851563050763829 0.01377781454919901 0 +-0.05580629977280413 0.006252843553719746 0 +-0.02601320869001809 -0.07956552527571575 0 +-0.08123524689641412 0.0606405946955375 0 +-0.1370357174909877 -0.0008235630616006281 0 +-0.1175095183318214 0.07765751256428227 0 +-0.02819096356997615 -0.05000671331571013 0 +-0.07519883722579938 -0.02199741509841542 0 +-0.1543878251248769 -0.08671174180007087 0 +-0.03373955759854193 0.04116747462757363 0 +-0.1361944151020669 -0.01128823258533992 0 +-0.1433708973772001 -0.07166242183332754 0 +-0.08706138068680368 -0.05540040542009106 0 +-0.08412475469624496 -0.05026742315582358 0 +-0.1537958127112781 0.08545315436552529 0 +-0.05479370214877272 -0.05131529554956239 0 +-0.1534640900699406 0.02958901901130764 0 +-0.05708705164034437 0.0421358826858858 0 +-0.08267683723121555 -0.006452555057577071 0 +-0.016227118918141 0.07765372584193311 0 +-0.08249855054792141 -0.08690858098968318 0 +-0.09767503730834151 0.05272701615199515 0 +-0.07392891522410086 -0.01379664687819464 0 +-0.06935382965026442 -0.07882849331223181 0 +-0.03704513596424448 -0.05401631611899563 0 +-0.1447575972095242 -0.04262832295791321 0 +-0.02380304941221738 0.08571958341666747 0 +-0.126714201681285 -0.05028572410987667 0 +-0.01365280135375833 0.02765752613674698 0 +-0.1237384035757946 0.04962830460770924 0 +-0.107853786105829 -0.0944755447467176 0 +-0.03407159740670108 -0.07216679681396193 0 +-0.005253467286378872 0.07769043160550781 0 +-0.06703146720202577 0.03712243478968959 0 +-0.06088596767300981 0.06226903505755375 0 +-0.08538239411163684 0.08741119745929553 0 +-0.04602990890591687 0.01463098319706153 0 +-0.005781741431390118 0.05560611328557448 0 +-0.02604528584943594 0.04576199010073231 0 +-0.08284610283737685 0.003045413207587522 0 +-0.03014565978965645 0.03443698275067739 0 +-0.07421218473595588 0.02845521219935211 0 +-0.1336036222771573 0.07408948247395097 0 +-0.1093308085511378 -0.02965839587237641 0 +-0.005968345067303711 0.02456652731093714 0 +-0.1547308336679947 -0.07243059518685704 0 +-0.1018108665227462 0.04120155070450033 0 +-0.1556457466513375 0.007441303792070449 0 +-0.04980567678034153 0.06173583644485531 0 +-0.08074252118400747 -0.02943775273555849 0 +-0.09642376489108133 0.04292722773264741 0 +-0.113551882543242 0.01717609383805412 0 +-0.0243508262876361 0.06910929362204442 0 +-0.07379780082625072 0.08760749769002679 0 +-0.1059918799295378 -0.07381658894400095 0 +-0.1317628811266124 -0.03777705699139355 0 +-0.0529820470877021 0.08605081212683957 0 +-0.08362769116091928 0.07110742144037903 0 +-0.01558311003827795 0.0880246348088652 0 +-0.144416889961722 0.08802463480886517 0 +-0.03496963838123277 -0.0856182711967855 0 +-0.01381529309472112 -0.02693949799079085 0 +-0.06236582633892753 -0.09435295815581093 0 +-0.09554690348142851 0.06456406629554047 0 +-0.1078392883005275 0.03422455289835873 0 +-0.005279479874619329 0.08664862441969758 0 +-0.0145248326964969 0.05862882193098254 0 +-0.1147077925326925 0.04901952291652439 0 +-0.1034449587418947 -0.05832153404785399 0 +-0.03988567903915138 -0.0294309353669611 0 +-0.02613968463414476 0.07455951972166618 0 +-0.04967389785672513 0.03036603258186063 0 +-0.1545707305780517 0.06951277489088216 0 +-0.02854612884881823 0.02345962374158613 0 +-0.1062866293444533 0.08624509725203816 0 +-0.1362293751706305 0.08602788023414432 0 +-0.03451670291611245 0.07205112927732762 0 +-0.09931894839332484 0.03064439144242118 0 +-0.1274506243007134 0.01767223352717415 0 +-0.1155988209787977 0.08784014868603007 0 +-0.04179779097923975 0.0481582611167496 0 +-0.09319240047717094 0.03775611874597481 0 +-0.1075517021984319 -0.05407966871005578 0 +-0.07166426438407814 -0.08862086483366377 0 +-0.04365417061123616 0.08796505195453938 0 +-0.1058428187113268 -0.04909635343916589 0 +-0.1272137470875786 -0.07259819017776886 0 +-0.04293357782612868 0.02379476149749506 0 +-0.02474570864572836 -0.0117797753742187 0 +-0.03251493944318865 0.09542371317587278 0 +-0.127480307732535 0.09542776213995255 0 +-0.1400730455309802 0.01858517372013556 0 +-0.04488038826556804 -0.04618565109111837 0 +-0.01926064442410149 0.02284225542851023 0 +-0.1327568702185024 -0.02757447918707193 0 +-0.1252607442608327 0.07418823932521074 0 +-0.1482924950532183 -0.06120419744090153 0 +-0.08646001873713811 0.02879784626052228 0 +-0.1161984319915629 0.06903749867536763 0 +-0.1058608031167727 -0.0387638293570662 0 +-0.09810359186786535 -0.04206951501620787 0 +-0.09342551825173052 0.04720704548407617 0 +-0.07814720314132106 0.09468092510836762 0 +-0.1349712122308432 -0.01729500202884257 0 +-0.06073030940295082 0.07695300157431285 0 +-0.01203981443512122 -0.06366132901230853 0 +-0.09308095006049981 -0.06201978072334054 0 +-0.1205614488047381 -3.293949301727919e-05 0 +-0.04047727957764489 -0.0155070235568811 0 +-0.09107555186836319 -0.07150564776902096 0 +-0.0449575102626002 0.0791851672246128 0 +-0.004986094520115586 0.001793703649316217 0 +-0.07626754277115852 0.08171495864078797 0 +-0.06931268332444177 -0.06419792187194408 0 +-0.1456860933596505 0.05590380476107992 0 +-0.06801452571426546 0.06938463711917964 0 +-0.1123633611273515 0.03825259799581039 0 +-0.004422703852701513 -0.02232467999761348 0 +-0.03624430705624219 -0.01279522181199716 0 +-0.1070114347466325 0.02309538444578633 0 +-0.1365427887823629 -0.07716561405873035 0 +-0.0787096886383241 0.04109963045717582 0 +-0.1493150618811258 0.03069301600177821 0 +-0.05003669172803664 0.0760883803879201 0 +-0.09728285745477069 -0.05200934060889821 0 +-0.06765338532743911 0.00410383037115903 0 +-0.03678126016664955 -0.007102273330900335 0 +-0.03965692403334884 0.03245507855324033 0 +-0.1318700302961846 0.05373290990782516 0 +-0.1284254837411467 -0.08114414562592166 0 +-0.1168815367886987 -0.04698274034415071 0 +-0.03672478826957558 0.008885129508012094 0 +-0.03448200905828607 0.03082052526595497 0 +-0.1350311883165919 0.07000247582598118 0 +-0.07333490885730572 -0.00433246559665903 0 +-0.06286978116302915 0.02216034011953338 0 +-0.1219724016273114 0.0778826774100114 0 +-0.1093164728249041 0.09447820236949328 0 +-0.02186891878423734 0.005138197345164878 0 +-0.1153156670952566 0.05823879562879833 0 +-0.1477545524795917 0.0474951378265548 0 +-0.04580545168041907 0.06804408633854656 0 +-0.1290705192494697 -0.01931983931036291 0 +-0.1551502608836374 0.0523789106961591 0 +-0.02305186906834451 -0.07570725896419397 0 +-0.0877752042254536 0.03873841528110072 0 +-0.0819099782006423 0.01241928707477925 0 +-0.1472518772562566 0.01196790973368253 0 +-0.05632100867795398 0.01756791640425989 0 +-0.1552588676205201 -0.01259432372652647 0 +-0.04412261381613103 0.02897275812375451 0 +-0.02243950154896871 0.04052019433813581 0 +-0.06428391427629743 0.05105294462204813 0 +-0.1340309118420432 0.02710068767631933 0 +-0.0991175310243433 0.07337837644514787 0 +-0.06679793948223353 0.01243614010916102 0 +-0.05347116806575467 0.0266913666874087 0 +-0.03361354841452636 0.02552059136338677 0 +-0.09191692337228957 -0.01160997419716477 0 +-0.02169392375237051 -0.05969438849858494 0 +-0.07695702933266335 0.01288628869564715 0 +-0.006047147997654865 -0.03923047942826296 0 +-0.04121226474800262 0.05910139900382913 0 +-0.0666400886914176 0.03195500412068884 0 +-0.004411000776417122 0.01189330513237254 0 +-0.07344325841573378 -0.03720133885152867 0 +-0.1049431351965206 0.04585401249817214 0 +-0.004026439343402639 0.04224313070181279 0 +-0.06647694030860506 0.08517647573374294 0 +-0.05565591073393723 -0.02014964836704344 0 +-0.020993407695413 -0.0655568649449831 0 +-0.125514145061373 -0.03286450834193509 0 +-0.09970493452200177 -0.03159640170708305 0 +-0.04758926853324881 0.03960997919918729 0 +-0.05193932360879636 -0.001664249431484463 0 +-0.05596991353353356 0.03695921718419116 0 +-0.06204058928333773 0.003802085114274578 0 +-0.05087050576585699 -0.05408520493151207 0 +-0.04100408264343202 -0.07754247775081302 0 +-0.1037582152529084 0.03695084836773902 0 +-0.05197567312826779 -0.06819472453643215 0 +-0.154855038778143 -0.04399225939464702 0 +-0.04648151387843091 0.00641936482517989 0 +-0.03770835272617109 0.02221329983671661 0 +-0.02116154914917615 0.01439245468071413 0 +-0.1279513224990098 -0.009891502745760486 0 +-0.06455171753876116 -0.08843645914939804 0 +-0.0476775154839594 0.09538247152374808 0 +-0.04680346909976303 0.0201548977081773 0 +-0.08728954799617952 0.01872030532056865 0 +-0.1396389763899057 -0.06710047260958038 0 +-0.1024471952695379 0.0256917438097392 0 +-0.1376244502625559 -0.0951796189033233 0 +-0.04686287458595719 -0.02370545986942339 0 +-0.0925352270777572 0.01130661956746628 0 +-0.01326306072101983 -0.07760206472825013 0 +-0.07804531378906787 -0.05988325331715096 0 +-0.117051546908407 -0.09538770965911018 0 +-0.1487552074396941 0.06004385382410055 0 +-0.004823940010597426 -0.00768466431908992 0 +-0.0639249845883558 -0.04732561901986175 0 +-0.004836521323878686 0.03277841097228364 0 +-0.08740531182908877 -0.09532182498598807 0 +-0.07447824981944139 0.01738486214764938 0 +-0.01368826167627486 -0.03687462696644789 0 +-0.05456374363057044 -0.08883499349071199 0 +-0.1548400651556359 -0.07793580306243009 0 +-0.06611528315315188 -0.004899908608427548 0 +-0.01729735302988064 -0.08711818939273661 0 +-0.09082727263131064 0.07775454896292802 0 +-0.09177910607992996 0.02722822363208244 0 +-0.104525033667085 -0.02239289061036329 0 +-0.03294332646493699 -0.02251600946898424 0 +-0.07510705650856321 0.03782125938131801 0 +-0.1237310812060011 0.01417977249978881 0 +-0.09810115149972781 -0.0597514175645634 0 +-0.07440220941450566 -0.07001776615690006 0 +-0.1206537622222105 -0.01538101660931963 0 +-0.1554203234596525 -0.05589539127976803 0 +-0.04911143770433349 0.04363169267205608 0 +-0.1301887759721533 -0.06082212622464504 0 +-0.05082691735585111 -0.01875475977027216 0 +-0.02293163950004876 -0.02165315809748589 0 +-0.01828601287672759 -0.02010716846585544 0 +-0.05443455107896131 -0.01014015424660905 0 +-0.01782338360743969 -0.05093367814145447 0 +-0.1057045635326466 -0.06343586119718622 0 +-0.1484073983521187 0.08482417195272643 0 +-0.1075179088160337 0.06170465744036746 0 +-0.1488762520438013 -0.09425307905959175 0 +-0.05809311974690179 -0.02744395906984191 0 +-0.143424925528613 -0.07644493541609015 0 +-0.1332610627722831 -0.08881118337942684 0 +-0.02138073355332695 -0.03629906625671973 0 +-0.02440768235399348 -0.02671894010184391 0 +-0.1144623135478468 -0.05869557356096098 0 +-0.0556190161898646 0.04695143837636379 0 +-0.1112477386624252 -0.08227531480083597 0 +-0.0197764485614343 0.0669334099857386 0 +-0.01123622462867454 0.03899057452755395 0 +-0.07600931198035046 -0.02735112540212176 0 +-0.01090004014786407 -0.04578443168595699 0 +-0.004612463609372891 -0.0622922198406597 0 +-0.1027614692987147 -0.06832432540812897 0 +-0.03771587761877155 -0.09526446234020136 0 +-0.01258666009471533 0.08402870253856108 0 +-0.06774450550961124 0.07879112492988789 0 +-0.1185186185464814 0.0301265529787676 0 +-0.09171975116522646 -0.08841828572248574 0 +-0.04649035388034399 0.05070780100546114 0 +-0.1366012833891398 0.09544176691465661 0 +-0.0234122894294518 0.09539204348700731 0 +-0.1358395476260128 -0.04686469048056349 0 +-0.1427324836555756 -0.00241319288813845 0 +-0.03688452331768304 -0.04498402126612376 0 +-0.0641637002286426 -0.08052144820838139 0 +-0.04363583574912498 -0.07018973081427091 0 +-0.1205822232442456 0.004878188447065562 0 +-0.119483176858936 -0.08556169855167468 0 +-0.1129410582085587 0.05365433445756641 0 +-0.09832982793693347 0.08140380619499307 0 +-0.08773277017915639 -0.04518362034919421 0 +-0.09209488840898614 0.01719279089194549 0 +-0.01178528994235394 0.01734026721222505 0 +-0.09306071675107473 0.0962263520690687 0 +-0.05927855714512786 -0.01231193662899639 0 +-0.1177055790775037 -0.07704154785702953 0 +-0.09614680867334546 -0.07330849226143903 0 +-0.06109863322547276 -0.07234214875733117 0 +-0.02901070747012853 0.08265717437864463 0 +-0.1394920950940016 0.07878507889050185 0 +-0.04559886773319891 -0.06164882611805915 0 +-0.07144452288977435 -0.03146531320481168 0 +-0.1389924859838484 0.06036199247360644 0 +-0.06369143709043423 -0.03546369210869665 0 +-0.03109728358356851 0.01562132106196209 0 +-0.1240442421005697 0.02731474743855938 0 +-0.1099118349660462 0.04411861096148571 0 +-0.01121481537212196 0.06647252594255262 0 +-0.07198493754869596 -0.06002472430496941 0 +-0.09937940664196561 0.05700503720407021 0 +-0.1123683616066731 3.711939438182764e-05 0 +-0.03025242167016464 -0.005059082579972292 0 +-0.02468566274436353 0.0311849066326032 0 +-0.1323271403600206 0.05821265034614701 0 +-0.04568517133827234 0.08346667222638016 0 +-0.05987280146307133 0.07179942505663993 0 +-0.09502312795602205 -0.003278338473491196 0 +-0.09526473530672587 -0.08133703321991345 0 +-0.08151607764508699 -0.01087240078201559 0 +-0.1190694539636675 -0.07128988593732014 0 +-0.06517594596296211 -0.01152996814082208 0 +-0.06602233254002751 -0.05409956180749703 0 +-0.1419864144230926 -0.04670064018371345 0 +-0.1239241325643014 -0.0875763004108973 0 +-0.1476351414247646 0.06774138803443631 0 +-0.08969749845613334 0.05671370830532561 0 +-0.147793539924003 0.02211814746862266 0 +-0.06960676037505287 0.09494367075138635 0 +-0.1111106292162182 -0.07194174391802839 0 +-0.08386216988946488 0.07845661044852634 0 +-0.131041499752889 0.08297609884492692 0 +-0.1390123950521259 -0.08540688904047537 0 +-0.05804297362294646 0.02759399850923764 0 +-0.02420216378437483 0.02551768135139138 0 +-0.08850266485629975 -0.03102363302555826 0 +-0.004654057801887219 -0.01327701821563941 0 +-0.04858717386089695 -0.03989111125223626 0 +-0.05276634305078184 0.002444268387450185 0 +-0.1410714127192279 -0.03396124679970432 0 +-0.0884903830255625 -0.01499810052409652 0 +-0.03385977466426845 -0.03101302737956101 0 +-0.1041280210863496 -0.00127568270117092 0 +-0.05965168947496485 -0.07746341942612792 0 +-0.03040662085658467 -0.06210427174742363 0 +-0.1124632798676241 0.01164690638071108 0 +-0.1553835216298238 0.02470218719248832 0 +-0.1555043527351167 -0.003302238596373637 0 +-0.01315794847269021 -0.008221035775517917 0 +-0.1494322811428258 0.09555404622944814 0 +-0.01059350851634249 0.09561305810195572 0 +-0.1088678065672323 0.07568434129836704 0 +-0.07016215676283463 0.04523892764234577 0 +-0.05665497774345656 -0.03545096533045486 0 +-0.02028931033881834 0.0788074546667962 0 +-0.005595718463276549 -0.0307299926523413 0 +-0.05099170863236497 0.03556067763508462 0 +-0.0107072673484008 0.0339880740005182 0 +-0.04194476146853912 -0.03682060647719892 0 +-0.05761948220980821 -0.09603576715833895 0 +-0.08586353006920594 0.03397875970580964 0 +-0.1277405703638289 0.006891686758114806 0 +-0.03109520569186376 0.04561455161133714 0 +-0.03004112263675891 -0.09522979782232853 0 +-0.06973735217219439 -0.04522195138261593 0 +-0.08958045076293913 0.06540500042904551 0 +-0.1212257857530482 -0.03420147835281517 0 +-0.09604973910037093 -0.01883276171626849 0 +-0.07688058719940988 0.04618066085869576 0 +-0.1372220715383965 0.05178749405317454 0 +-0.01104032798270374 0.04840082152491862 0 +-0.08811426278261604 -0.07950993008875498 0 +-0.1238036501368432 -0.02330427234237821 0 +-0.1358962145816022 0.03558690326329245 0 +-0.09516637548339339 0.03348616704710229 0 +-0.09736456828115395 -0.09545621213879298 0 +-0.01978763988488245 0.06192276516585034 0 +-0.07754535854826429 -0.09589628328051218 0 +-0.1355632163516451 0.04262487888562934 0 +-0.02548629569147114 -0.05715484212732434 0 +-0.01627476102213025 0.003693839611705862 0 +-0.04513282289850014 -0.009221352135882445 0 +-0.1401262609193791 0.02817826121677254 0 +-0.1431571668994246 -0.02631709985345763 0 +-0.1076306672695124 -0.08397616925052266 0 +-0.1242238109656958 0.06925116266613347 0 +-0.01592145704192706 0.05397822510247954 0 +-0.096012707401925 0.08891637845141576 0 +-0.03876024462771295 0.09545635137868537 0 +-0.1211742181765407 0.09536186166700833 0 +-0.06871310653364596 -0.07388610201753498 0 +-0.004870394855692998 0.07174778508475965 0 +-0.0906384104803844 0.08710809517261221 0 +-0.05520221072465509 0.06477386732066683 0 +-0.004454451297267703 -0.070354264408859 0 +-0.03596329513547739 0.05765855856739292 0 +-0.1082462197151013 0.07139274669077811 0 +-0.01055364157439866 -0.03211942926986525 0 +-0.1561116856421383 0.06280824148790864 0 +-0.07062568367202104 0.02485924153514699 0 +-0.1135691580589667 -0.02152586989759328 0 +-0.04944174825334212 -0.03152067204507964 0 +-0.1551285623885252 -0.03608860691847546 0 +-0.06978999790421264 -0.04015609578414469 0 +-0.1036284145818214 0.06525856920074323 0 +-0.03777602353099391 -0.06894859412826018 0 +-0.1107905080010619 0.08464592120051118 0 +-0.06932916304483323 0.01675587092951625 0 +-0.01032395865947069 -0.01530285851337794 0 +-0.05337101033547927 0.01326880754215693 0 +-0.04478905812798497 -0.07511843804205606 0 +-0.1237995534232874 0.05517100100467706 0 +-0.02366089224009899 -0.001824895314666151 0 +-0.1443431704281046 -0.0550027267041254 0 +-0.03880153629546308 -0.002511592009937579 0 +-0.1424947614068195 0.01410611680712306 0 +-0.01144250999166324 0.07851792314857868 0 +-0.07848681952370286 -0.0528692967942873 0 +-0.09308729419723183 -0.04584387369505485 0 +-0.03514133354487956 0.06731256456393078 0 +-0.07882841979794575 0.02515907509432147 0 +-0.1561508987141898 0.03688268296411491 0 +-0.126012912112021 -0.01540110045477914 0 +-0.01038036378084732 0.02517170756316963 0 +-0.1062879260766298 0.006930401885537285 0 +-0.004442806546549182 0.06383726988215427 0 +-0.06258115906190136 0.0886780293382583 0 +-0.1279335857375937 0.09066234659271746 0 +-0.03257380434206946 0.09030620326578574 0 +-0.01978442989058544 -0.01215232261644675 0 +-0.03730937699045096 0.08029423268042632 0 +-0.05028801907737913 -0.06320836963708606 0 +-0.0455358275792906 0.05820041416064642 0 +-0.04042322844422325 0.03686522932261316 0 +-0.1048863243882085 0.0573639656241418 0 +-0.107687534170137 0.05351927992194062 0 +-0.09292482981071472 0.07335636557535374 0 +-0.04209591835639635 -0.09607384191009354 0 +-0.09873008827419361 0.02209282474870638 0 +-0.003915538165567338 -0.05807375637118132 0 +-0.02814609257968407 0.06111075977239064 0 +-0.0171217834590105 0.03119594423692012 0 +-0.05217421611760747 0.0215860766153205 0 +-0.1200114584606299 0.06693467598398113 0 +-0.01839310023630965 -0.0955741404022119 0 +-0.1265920212619722 -0.07713839492838674 0 +-0.1156590797390841 0.0263130589981482 0 +-0.08008571095945376 0.05306131651014261 0 +-0.1313871816691726 -0.06551166485546428 0 +-0.1272739553486572 0.034845926575973 0 +-0.1495693395196356 -0.03594709031289179 0 +-0.004091604530037193 -0.08161554239683667 0 +-0.06579762402907563 0.05979218184263693 0 +-0.02216918932012335 -0.04080429243023832 0 +-0.116038481478067 -0.002257392381397185 0 +-0.07825894877019049 -0.04386294996007171 0 +-0.1084038246916866 -0.04449783349097049 0 +-0.1562935939457955 0.08164289042950262 0 +-0.119005413100199 0.04734619591338227 0 +-0.04787526742770376 -0.08290709620982419 0 +-0.1010858192637937 0.07773336660798613 0 +-0.137059215144281 0.008618219844619471 0 +-0.06231478052249097 0.01256123293991603 0 +-0.1110565748247768 0.06425719849092967 0 +-0.076976779763216 0.06234949568425425 0 +-0.1275372022743013 0.04445875990675233 0 +-0.12075639062588 0.08682431492754712 0 +-0.06446637598945539 -0.06315072317093932 0 +-0.05660474797797935 -0.04106890147253957 0 +-0.02848997775868736 -0.04502488985851668 0 +-0.1049048788837688 0.01498378417320717 0 +-0.1055838403591255 -0.02623438658662752 0 +-0.07826612889555075 0.07225527185629228 0 +-0.1356021288644149 -0.0410779270813503 0 +-0.03912554305298259 0.08724949725237122 0 +-0.1469870458071542 0.08044910799645769 0 +-0.009879500078844658 -0.02260144134175701 0 +-0.14894517899566 -0.06950072972367613 0 +-0.1117928004202441 -0.01454804803979792 0 +-0.1406765753796337 -0.03873234921427257 0 +-0.09704030585482185 0.01111802670293181 0 +-0.06952930311515255 0.008821669009534646 0 +-0.02505699347524861 0.09017924863330488 0 +-0.1331500146051005 0.01364365546275559 0 +-0.05503207577640958 0.06946738314035769 0 +-0.05111899747980797 -0.07970593994957137 0 +-0.1190822477910343 0.01581168723691196 0 +-0.03935332043681684 -0.08705949218947638 0 +-0.02152017472234052 0.04529790973056071 0 +-0.1488324598543956 0.07691313555989887 0 +-0.1120423113248045 -0.06718287339487133 0 +-0.119171238084629 -0.01003038794526377 0 +-0.06192371115772063 0.0421870921484432 0 +-0.07552347325598649 0.06711285963309144 0 +-0.02288548383612692 -0.05016727083530797 0 +-0.1243991313775899 0.02230391421034631 0 +-0.003724841061489002 0.08250000000000003 0 +-0.01083896928171529 -0.05495469502504415 0 +-0.1199046894624662 -0.03852039318304318 0 +-0.07339370229557947 -0.05161142323565242 0 +-0.1182983300376073 0.02125769490220209 0 +-0.04570562627213112 -0.08979279900382936 0 +-0.09872903886689169 0.004361213779230867 0 +-0.05049279463054286 0.07143205187261181 0 +-0.05840946000352059 0.0569335012728188 0 +-0.1486874117791119 -0.08404777720861578 0 +-0.148997615733949 -0.008333360901883807 0 +-0.06215104428935665 -0.05610820218841352 0 +-0.09214107874221403 -0.05343080553529176 0 +-0.1552559923601607 -0.01728538481251092 0 +-0.1160233162484283 0.007242366865812764 0 +-0.02852439159383671 0.01886403625539786 0 +-0.06953803036084054 0.07407277857388517 0 +-0.04027127206954949 0.06554070152055873 0 +-0.1406648495088566 -0.06211148130196628 0 +-0.1371734722010289 -0.02475261440515203 0 +-0.1431540634941856 0.02149757281406713 0 +-0.1406789934134877 0.0560904711793513 0 +-0.1013795960937252 -0.04875507479440802 0 +-0.07341147538917887 0.001444208498736581 0 +-0.07678980391334649 0.004487650139063631 0 +-0.1488123813714152 -0.04039086096714074 0 +-0.10256768119222 -0.09542477902170876 0 +-0.1483358232084945 7.577540456245406e-06 0 +-0.1077869300728002 -0.007252352316872521 0 +-0.1555964176085906 0.08993712921710885 0 +-0.07085840900763665 0.03933907504158635 0 +-0.1447133357204548 -0.01501380821809544 0 +-0.1142881976905315 0.0817470175213883 0 +-0.1040905443407268 0.06968419627973671 0 +-0.01446779937163208 -0.04216196791806126 0 +-0.140488765272812 0.06449933468356997 0 +-0.08154649968156333 -0.002041225716633401 0 +-0.06338117816162057 0.06799750409130831 0 +-0.1119058312199924 -0.05534213325066195 0 +-0.07629772525023173 -0.01709242343422127 0 +-0.004106799533510094 -0.04402601352634406 0 +-0.1237680123270427 -0.007682467790810036 0 +-0.1433184849654831 0.07227730266198341 0 +-0.08332652736519007 -0.0719963748230642 0 +-0.04114875792406142 -0.04436934340854502 0 +-0.09215943065087361 -0.02673608472112566 0 +-0.04239428440163983 0.07053531662751457 0 +-0.02428699091841793 -0.08988759231820291 0 +-0.1291488845993111 -0.001814167434973239 0 +-0.1001968635687292 0.01740044233157438 0 +-0.1403956094166509 0.03487574399587997 0 +-0.134975599314822 0.09031981818268843 0 +-0.1492967830799044 0.03929473903581275 0 +-0.00991592683588486 -0.09605668127870701 0 +-0.06583818467998141 -0.03167727379255571 0 +-0.1560589361067419 -0.06448997457321609 0 +-0.07283831735954718 0.05484896168018655 0 +-0.1016002436826084 -0.03931963655148797 0 +-0.03252267575190039 -0.01511224545572005 0 +-0.1557323072179373 0.01638236439422726 0 +-0.05770934970978672 0.09632434212810613 0 +-0.06511185743353881 0.09567068065234427 0 +-0.04407237092401491 0.0005616994069759585 0 +-0.03733712600148131 -0.02255700855489102 0 +-0.1033549078070662 -0.07724774368373963 0 +-0.04772017606823254 -0.00205023215599049 0 +-0.01020261312180538 -0.08453075252001156 0 +-0.1146762330440204 -0.03969134831303622 0 +-0.03117672345805013 0.07525252442413906 0 +-0.118855546424745 0.04216548327986404 0 +-0.1119016117388884 0.06845809517583619 0 +-0.1560125402232399 0.003361726127975292 0 +-0.03599069237996017 0.01742669006300723 0 +-0.1558708763324743 0.01207132868135516 0 +-0.004030621700134745 -0.09004588746755729 0 +-0.1348205340062754 -0.006167984391079751 0 +-0.04173257130021696 0.00556869397776295 0 +-0.02742290441242761 -0.08343148771893906 0 +-0.02670497127111261 -0.07289658171064552 0 +-0.1317636098473758 0.06697184029208048 0 +-0.0376270539101862 -0.06253249668925569 0 +-0.1280078800483498 0.06686790668808303 0 +-0.06990956416595989 0.08796140292767665 0 +-0.05250000000000001 0.09652896334143357 0 +-0.09946651325997152 -0.02262133112220512 0 +-0.05915809174411463 -0.01741641103808425 0 +-0.1139449669260328 -0.0327830160583136 0 +-0.155733427586455 -0.03016394359319305 0 +-0.09679921465769743 -0.09038757548441086 0 +-0.1014449411378976 0.09598705443921411 0 +-0.04969433193113269 -0.02755641488448158 0 +-0.05287872473912925 -0.05966558731554912 0 +-0.05321006813246711 -0.07276281247685697 0 +-0.08424050959246471 -0.02532896858465757 0 +-0.01096807077508833 0.00643424476143088 0 +-0.0113964257033694 -0.06782214424770303 0 +-0.0200330141249769 -0.004051168970989712 0 +-0.06558695978372855 0.04637562021617148 0 +-0.155901444453683 -0.02221986868567117 0 +-0.09021842579435789 -0.06621301146109476 0 +-0.1375697474577178 -0.05875246428942821 0 +-0.07021788293590447 -0.05510706595663271 0 +-0.1327848933692895 0.04960534199750256 0 +-0.08164423404967602 0.03238196688975918 0 +-0.05999182227922417 -0.004472972040730076 0 +-0.07206192849716783 -0.08317301074191702 0 +-0.09953355343595256 -0.004781764418535209 0 +-0.05340111201273916 0.05652296207196537 0 +-0.04415456267230698 -0.01331803901018294 0 +-0.08813958823337847 -0.02240758506591227 0 +-0.01380634873724091 -0.05893290473193079 0 +-0.06701238934550949 0.05460061989595082 0 +-0.0881730683962459 0.0957383339339222 0 +-0.02736685720788322 0.06618409959480472 0 +-0.1502237576863399 -0.02811913207658272 0 +-0.01446189682357183 0.04584473345707447 0 +-0.1405779967662487 0.0863002850431306 0 +-0.01760119344699929 -0.02862359265941928 0 +-0.156350100336457 -0.04791881920899354 0 +-0.003376499738651668 -0.002499999999999992 0 +-0.1350700231038416 -0.03235049363441966 0 +-0.1216046715462596 -0.09610572298150338 0 +-0.09521242520058802 -0.03440718467645398 0 +-0.08295046394483138 0.09617386681614919 0 +-0.08500156024544454 0.06323072494495342 0 +-0.151313064570204 -0.003353776380730216 0 +-0.08894592219287015 0.00186161142022815 0 +-0.08343412716643515 -0.06000357822198454 0 +-0.08017739795571149 -0.03458289567682304 0 +-0.06188763722887943 -0.04239380109792898 0 +-0.08515571251898488 -0.06468377925550482 0 +-0.06749658745681678 -0.09640163536841989 0 +-0.1486397218572181 -0.06537416932749454 0 +-0.003872452441980936 0.05925223395943142 0 +-0.01849290308898704 0.03852570811374723 0 +-0.003840357564149715 0.01673424992629016 0 +-0.07049623638028339 -0.02236046599176515 0 +-0.1030078961651484 0.003018831652079956 0 +-0.1243657507754901 0.0599626284435565 0 +-0.156519202531281 -0.08241580228841065 0 +-0.1408215106811806 -0.01082055821114666 0 +-0.03035434035791151 0.003926445218292974 0 +-0.07816163994079794 -0.08536720765399276 0 +-0.01935871574492616 0.08627925277752994 0 +-0.1133300309100312 0.09622626634318993 0 +-0.09665663451406216 -0.06440254517509725 0 +-0.01920772731470765 0.01830423221079422 0 +-0.06036407420192189 0.01890560167143511 0 +-0.08859625645204225 0.07017553687023848 0 +-0.02321027121077259 0.05875594039457539 0 +-0.05921359720384992 -0.06442784188314475 0 +-0.08422403029694875 0.008408396387224532 0 +-0.04219434188029708 0.01419513168076827 0 +-0.1128547972836418 -0.04553373690664342 0 +-0.06964813155286018 0.06206734316665449 0 +-0.02579415280488989 -0.03086227158050428 0 +-0.05982565322283259 0.008883671520782134 0 +-0.04809486379086952 -0.04372124778354815 0 +-0.1273737366469222 -0.03994901285114119 0 +-0.02535955052229001 -0.06696104723751639 0 +-0.1285986153889854 -0.09090922647080013 0 +-0.04703583175203884 0.01056209371076567 0 +-0.1413315899056473 0.09596651905286423 0 +-0.01841487247977563 0.0961999777931332 0 +-0.1498728435639995 0.01698142421047196 0 +-0.1081322421929482 -0.002258866239258685 0 +-0.08770522044296104 0.05200866696958482 0 +-0.004054948447262159 0.05138535594153541 0 +-0.06980214180198199 0.02920072946740854 0 +-0.07329093710375909 0.0595048100563312 0 +-0.07112618704796311 0.06656523888456098 0 +-0.02876481994346304 -0.0588014286268411 0 +-0.06015592015695187 0.05256050423456507 0 +-0.03380743033644877 0.04978004531409104 0 +-0.03183397000302414 0.05378357063795521 0 +-0.003759270966377249 0.02834735791083397 0 +-0.04223133936769556 -0.03310717742464431 0 +-0.1287236864900134 -0.09609803526988552 0 +-0.1156881286045593 -0.09031083832090865 0 +-0.06972206809635803 -0.01322646338101392 0 +-0.07649698908849906 -0.07758520998340772 0 +-0.02251982372054911 -0.09673957664707619 0 +-0.09646687009928362 0.07026104814433341 0 +-0.1233503911947548 -0.07065307574788281 0 +-0.07832990028388445 0.08600933376781164 0 +-0.09976032874009562 0.06394808416829695 0 +-0.103926400810731 -0.01497792687495989 0 +-0.09844900100714513 -0.0688170166952423 0 +-0.0913491381640841 0.006044293759234953 0 +-0.07795227977073464 0.02044136905492004 0 +-0.02967832529408587 -0.0328894988786759 0 +-0.05459808780989752 -0.046536117670049 0 +-0.1004460666999324 0.09099731967732552 0 +-0.1034463564420264 -0.08163285165249934 0 +-0.01144979929731917 0.06262716080569589 0 +-0.1186947903592385 -0.02699598471739876 0 +-0.147996317154414 0.03491449644277647 0 +-0.03138057679177464 1.869865846291158e-05 0 +-0.00363029315126199 0.03769819011162218 0 +-0.06532651374452259 -0.07057226961344096 0 +-0.07823784560920449 -0.06603225097362726 0 +-0.1562704754617008 -0.06851726267152691 0 +-0.02235732437552041 0.05378493937012285 0 +-0.08373012308111395 -0.01518608846765094 0 +-0.009862974443010868 0.05730392201755977 0 +-0.1155146229403802 -0.006813974776006893 0 +-0.01890651266299859 -0.08270911707085554 0 +-0.1035357831420557 -0.09073404155519245 0 +-0.0170928992201044 0.01146096650923806 0 +-0.1386537113796522 0.08275026805583673 0 +-0.1421820550057537 0.00536910679301152 0 +-0.08049703309751702 -0.01913213387736121 0 +-0.1316827747789495 0.07830741219135026 0 +-0.1225178377528292 0.03632590305895067 0 +-0.004319435087796135 -0.09569674417769441 0 +-0.09721977160750057 -0.02698606863726277 0 +-0.1272659734315089 0.05308622395005891 0 +-0.06322452100949544 -0.01985155532626022 0 +-0.06647144909666047 -0.01659840157949921 0 +-0.06000786006207124 0.08289566820452042 0 +-0.0255605837299418 0.05103227081006269 0 +-0.05057026860554884 -0.09599804251216464 0 +-0.004008534079911578 0.09051340677789486 0 +-0.02789766000818153 -0.00925537194557452 0 +-0.05799343702852958 -0.08517379494447835 0 +-0.1344487144948737 0.0215724581673326 0 +-0.03617430701284388 0.001045721270664785 0 +-0.09101684607906424 -0.001924941621566616 0 +-0.004031161972593029 -0.04991732783320399 0 +-0.1494675905984549 -0.04985611162260671 0 +-0.05310704294469781 0.07885969918556733 0 +-0.003514971944606363 -0.07798866634244703 0 +-0.07833228829807679 -0.004064941867988807 0 +-0.03127191869238954 -0.02564695407249029 0 +-0.04101333680280136 -0.05467902874985471 0 +-0.07368189427673946 -0.0466230651361737 0 +-0.07436707132821511 0.009042552960127345 0 +-0.1280712185854068 -0.03593646873708221 0 +-0.0633168745152516 0.03511198595949075 0 +-0.06554478175517067 -0.03890032849470949 0 +-0.08870315534429363 0.009475330722923607 0 +-0.07373364229349591 -0.009216816024341972 0 +-0.1097344715815857 -0.06389537482242748 0 +-0.1131025542831026 0.07705780821121409 0 +-0.08332638746507601 -0.03739818724238731 0 +-0.1051712826826188 0.05037684198684535 0 +-0.1353687479929636 -0.06761134252704065 0 +-0.04424346306589917 -0.05771282511772882 0 +-0.1341363392396341 -0.07419500915242475 0 +-0.1518051110374731 0.009783326057709691 0 +-0.08652321744758441 -0.08666006187977862 0 +-0.06153113463073856 0.02605401841083461 0 +-0.003580195175689426 0.02119513275280782 0 +-0.1401651018461914 0.04854966561573527 0 +-0.08373336177885626 0.01649237540954728 0 +-0.1321464176742732 0.03233445197275037 0 +-0.01741724358334514 -0.0355112914587437 0 +-0.1420653364300525 -0.01861385077289578 0 +-0.1461076483391448 -0.04671289631314408 0 +-0.02614311771056779 0.03625565586352955 0 +-0.1125 -0.0969087355425111 0 +-0.129675962952624 -0.04773257668547315 0 +-0.0583638058943658 0.09101514058264086 0 +-0.02623818497303258 -0.01887497124384845 0 +-0.003727398613613534 0.0463611900046797 0 +-0.1568369401591994 0.0729163411613378 0 +-0.04006956985444495 -0.01944040955735309 0 +-0.01514214947797088 -0.02278192481007951 0 +-0.09237325808035943 -0.09650295797211228 0 +-0.139347863586884 -0.05505277996156205 0 +-0.1375561499282185 -0.02044357939994018 0 +-0.1521416122998444 0.004734490104919413 0 +-0.03691764155710173 -0.09036295140613333 0 +-0.09443988237761998 0.05498718172052187 0 +-0.02144738141772205 -0.008454857434204271 0 +-0.149883181009983 -0.01776516927142025 0 +-0.156162338317489 -0.09616869092702003 0 +-0.08040977226759018 -0.04813473358741543 0 +-0.01834753170913804 0.007239759930942825 0 +-0.1294216205648067 0.07504877516120288 0 +-0.05612481357270397 -0.08083476347282137 0 +-0.1561074942970905 0.04442466265797682 0 +-0.1564402030474648 0.07745105830278361 0 +-0.1503556163903757 -0.0790844585874165 0 +-0.1203083665962243 -0.05428782817581244 0 +-0.08809718167578011 0.09039193990570224 0 +-0.04068478411230879 0.0442936299347555 0 +-0.13303188797883 -0.09611527217423572 0 +-0.05615993024739715 -0.02460944357110646 0 +-0.1228544148518199 0.08247244781166929 0 +-0.009617167061499956 -0.006542855597367068 0 +-0.1162891852970094 0.07368651553780192 0 +-0.0530435341770138 0.04402737564545202 0 +-0.1230264637821035 -0.0626579353870417 0 +-0.1409390876993643 0.001676443393361829 0 +-0.1201629900552261 -0.08022791287243045 0 +-0.1464751802802345 0.06388944596184293 0 +-0.1414227821582846 -0.09619118146677157 0 +-0.08257430847036711 -0.06762588933581665 0 +-0.1131156832399798 -0.02540758577408663 0 +-0.06274242391751095 -0.08480756448106849 0 +-0.09666643838248282 -0.07764704198338586 0 +-0.08369439370913251 0.05069441808738219 0 +-0.1360699725084249 0.01717946598002821 0 +-0.07478490537233139 -0.08599813343774235 0 +-0.11785964761062 0.03510416242715719 0 +-0.009048027919436328 0.08555988398244953 0 +-0.09162428591297408 0.06128057136572473 0 +-0.1175 0.09701447081050793 0 +-0.05909421566944196 -0.04944356127998589 0 +-0.05882342811068807 -0.05379695527470938 0 +-0.02111132148358533 0.08268056891393526 0 +-0.04341868362565902 -0.08167307232008164 0 +-0.1395023077433962 0.06918941602741979 0 +-0.08387490727716804 0.02567220099667567 0 +-0.1320254541001916 -0.009628163370631316 0 +-0.1439701109896415 -0.006386137066092514 0 +-0.01025966430929672 -0.0009897452376436966 0 +-0.05266522755411863 0.09042567792724801 0 +-0.07676363373697059 -0.07360865848374271 0 +-0.003666482574377392 -0.02683338097767406 0 +-0.1033832887657326 -0.02962689648030477 0 +-0.01556782521395853 -0.0001190613782354768 0 +-0.009836606339896695 -0.07557038729443426 0 +-0.1446721728927151 -0.02229735473259647 0 +-0.003173437402001718 0.0676054139778085 0 +-0.03222684193662236 -0.08921442879533026 0 +-0.02875591974421849 0.01065193846275168 0 +-0.01987822009590543 -0.04741269853036592 0 +-0.100538935193779 -0.008530944287377724 0 +-0.07330259985056935 0.09652012176247041 0 +-0.08485971373146711 -0.02943403834825094 0 +-0.1337412591861988 0.03910098738529368 0 +-0.1114208693228391 -0.00853938599467027 0 +-0.1424884382518436 0.04083243758576857 0 +-0.1197528903385201 0.06204148722561041 0 +-0.08652200448401762 -0.006600146880364916 0 +-0.1196652320397453 0.0086529504129427 0 +-0.02867369490421241 0.07844534330861333 0 +-0.1415034839580351 -0.09085948674647382 0 +-0.1565203252924677 0.0328073784838497 0 +-0.08474164009104496 0.05888648457432156 0 +-0.05010128241926516 -0.09159675942087499 0 +-0.1155347539332739 -0.07344241337514605 0 +-0.04318122286326269 0.03995212423396454 0 +-0.1068374379895127 0.09010400417244577 0 +-0.008374933168926244 -0.08907741584351409 0 +-0.1168872621046811 -0.0137028883864143 0 +-0.09390009417894821 -0.04956123687325148 0 +-0.1098754776867771 -0.07610617778012169 0 +-0.03274978333897032 0.06067627202187878 0 +-0.03456436318705816 -0.08119160728582983 0 +-0.04651631481860821 0.04679558911475847 0 +-0.08014337038948059 -0.08101574652033579 0 +-0.00839436805777743 -0.05020441032188292 0 +-0.038203702798576 0.0510401255018814 0 +-0.1292648711786868 0.03942494463919011 0 +-0.1465125555559982 0.05169942094013327 0 +-0.1438636042454402 -0.08278763723790161 0 +-0.01901410883389632 -0.04351395664174258 0 +-0.1515011784959502 -0.02379409879958324 0 +-0.1059868305487582 0.09644667174762953 0 +-0.009589012593876796 -0.03691555971085114 0 +-0.1559557368231253 -0.09199236969557922 0 +-0.09040245041609218 -0.05808117672176868 0 +-0.1295214824540993 0.003394358495512749 0 +-0.06618472197579328 0.0005980154996424263 0 +-0.08080167834315435 0.05685861365615177 0 +-0.1525506222612392 -0.09704049792337718 0 +-0.1008733296363674 0.05015977360205599 0 +-0.1571414805677453 -0.05250000000000002 0 +-0.1072374948643383 0.08262105509726711 0 +-0.1203792624693357 -0.01970594636902467 0 +-0.1296939632230631 0.02084610507740575 0 +-0.1168164118522624 -0.06650944046224279 0 +-0.02467693448540731 0.01048930700847953 0 +-0.104598611912357 -0.009823907847933033 0 +-0.1217162230041862 -0.045534574850372 0 +-0.1034392149570052 0.01020479228746397 0 +-0.1216197013704154 0.04008804747210067 0 +-0.007423380198203672 0.01536758778375067 0 +-0.003394665255159061 -0.06668076098520258 0 +-0.05089537674645502 0.05286570055289049 0 +-0.003742478473648518 -0.03556459207667359 0 +-0.03361179089395925 -0.0964805080742789 0 +-0.03302906185378016 -0.05317076707439387 0 +-0.05727766793189953 -0.07385146153025367 0 +-0.007609283463116508 0.04032944382911968 0 +-0.1571663533857059 -0.007500000000000048 0 +-0.04594422180488248 -0.04981155070482587 0 +-0.07318187623061786 0.04775106832843594 0 +-0.1511194579637876 0.04463909046593372 0 +-0.04930830204916194 0.08600757651542637 0 +-0.05818926981842749 -0.008317685497592825 0 +-0.06840555755770113 -0.02862662339407456 0 +-0.08069428500646204 0.04470995575291431 0 +-0.05927741096077526 0.03450510048500216 0 +-0.003123185636752408 0.007250033399210236 0 +-0.0406973979530533 -0.006679528812042215 0 +-0.1110580259083121 -0.09017056149198227 0 +-0.1193575469162181 0.09087625241967438 0 +-0.09838790965104352 0.06090937451218902 0 +-0.09345563650317697 0.08044255088084537 0 +-0.1336885432973592 -0.05899863134910391 0 +-0.06776817630948524 -0.02513847647333361 0 +-0.08385514608924276 -0.09064719375794342 0 +-0.09968533137663073 -0.08382072866067097 0 +-0.1344747530369537 0.004118962990976542 0 +-0.0292468057751152 -0.06562678622001286 0 +-0.1565104124575085 0.06638516362284097 0 +-0.07149962902739394 0.02011241512109864 0 +-0.144909344344047 -0.05938005422929625 0 +-0.130128039754637 -0.05282661952964586 0 +-0.03888858166183319 0.05523523849142305 0 +-0.01132151686980467 -0.09185766615782047 0 +-0.07874438563738871 0.03667636267902952 0 +-0.04773279848344397 0.06503042034670561 0 +-0.01031125218214396 0.07045395172343696 0 +-0.1561331406875493 -0.04068780867295756 0 +-0.03067358229226717 -0.0189398686003581 0 +-0.01395408131683684 0.01291454400851568 0 +-0.01663671773107974 -0.07953950652376501 0 +-0.0377450371234016 0.004366674958386901 0 +-0.009886583408600203 0.02180779947488162 0 +-0.06520051053977144 -0.05088728036680271 0 +-0.1002078843725815 -0.04529568737842101 0 +-0.01760894434712713 -0.01618414896795885 0 +-0.1086723684168438 0.0300175840622516 0 +-0.09258266816945956 -0.01541050666653576 0 +-0.03201430194984228 0.03803813910299032 0 +-0.07185594000412304 -0.06700018588216838 0 +-0.1360364872904966 -0.05203059628657378 0 +-0.003577881761394205 0.09711544826673812 0 +-0.1564221182386059 0.09711544826673812 0 +-0.04273730311912743 0.09707193817887308 0 +-0.09963133912448383 -0.01508530654227659 0 +-0.06801115964312403 -0.08858841019594081 0 +-0.1098117163874197 0.01462907941609522 0 +-0.1350963238130983 0.0606650289760477 0 +-0.09474860223651357 0.02987041207108962 0 +-0.03474556748095003 -0.04010647656182498 0 +-0.018220371223007 -0.05834407209294519 0 +-0.08715443575840709 -0.03609204333496985 0 +-0.04054478119392757 0.09100540014769355 0 +-0.09456965858483868 -0.03810867250229273 0 +-0.06430446547925373 0.07778029778573782 0 +-0.111191122294758 -0.01892558907435838 0 +-0.07623637596787078 -0.03984311588289283 0 +-0.05495910500740776 0.01008202927289416 0 +-0.0241127441621898 -0.03836083832307814 0 +-0.1126358768158035 0.09258756963157147 0 +-0.156982067078355 0.02805729465754477 0 +-0.08192560740720208 0.09186719936666987 0 +-0.09998515048101478 -0.08815280760423505 0 +-0.09015872029384314 -0.09277825305848329 0 +-0.1563100312521342 0.05616576437572895 0 +-0.1019418067382494 -0.03555885330560554 0 +-0.0188859395731748 0.0519169736556393 0 +-0.0255228901475689 -0.05319429204819541 0 +-0.008357109942763463 0.06437960716875965 0 +-0.1329418511035151 -0.002618683088463912 0 +-0.07341428292429306 -0.07937002310910213 0 +-0.08721005543963981 0.04467959295349686 0 +-0.09936539734430513 0.008532310934355846 0 +-0.1296781650381467 -0.0232697562461158 0 +-0.09645361058553049 0.01883927672921081 0 +-0.1438086194866815 0.04779929186560248 0 +-0.002928920436136147 -0.01759410981441749 0 +-0.1180741354102957 -0.03128888277807731 0 +-0.008320058899461025 -0.06282027764746886 0 +-0.134890606543907 -0.09261936274423441 0 +-0.1058274293982161 0.07877120773783589 0 +-0.0762968945123194 0.09033940878131269 0 +-0.1071332929828274 0.02700140903562753 0 +-0.01398417580463092 0.07379665561157077 0 +-0.03173812762141248 0.007414930574543232 0 +-0.02287977220206808 0.07655617727341324 0 +-0.1398615487445553 -0.07563728784359518 0 +-0.04691581814958953 0.0545136880739702 0 +-0.04213643929943557 0.07546788131779687 0 +-0.1150353704164769 -0.04359324825587124 0 +-0.03011235524883372 -0.07943402250794913 0 +-0.04961689623199407 0.01294544384067477 0 +-0.0309206104140632 -0.08595238194379874 0 +-0.03892333178382962 0.07336018610305348 0 +-0.1481116280605281 0.003609493872982817 0 +-0.09205048691435795 -0.02229336359347597 0 +-0.1507518217694957 0.04976334069725387 0 +-0.008787802718544201 -0.07112847728489607 0 +-0.1279120811729051 -0.03012120029966122 0 +-0.09316846173254625 -0.08431589687578823 0 +-0.1525000000000001 0.09735331019692617 0 +-0.007500000000000008 0.09735331019692615 0 +-0.09018635636473149 -0.03847682889678805 0 +-0.02496855634680258 -0.0154130186740665 0 +-0.1507956785339237 0.06958307476809721 0 +-0.06613586641413199 -0.06679276820656777 0 +-0.008799918906730739 0.003405294876931225 0 +-0.02974167663367645 -0.01238388305432222 0 +-0.01838115392348325 -0.07098681654957702 0 +-0.01337491215522088 0.03139609548585184 0 +-0.1206017496542319 0.01189927758084466 0 +-0.1232956181438069 -0.05788710954470072 0 +-0.1513047983219003 0.05637022807582717 0 +-0.01632816407877271 -0.09083542274603036 0 +-0.0975000000000001 0.09737457233386987 0 +-0.0839114984940478 -0.07747685190347597 0 +-0.1323384612768448 0.04597713710812744 0 +-0.1364281372979533 0.07672185643136506 0 +-0.03935229908356147 -0.02558904108390269 0 +-0.04261929298155711 -0.02641865616967928 0 +-0.01440878270942974 0.08070537742396838 0 +-0.07786288087944243 -0.01240174366129846 0 +-0.02397875255248385 0.002195272200730508 0 +-0.06423647110834964 -0.02427939381316616 0 +-0.1520163641076314 -0.04223971446205257 0 +-0.0274669212012876 -0.002515942765030167 0 +-0.01435270648809833 0.04160417901692588 0 +-0.07793660702037546 0.02953118093222754 0 +-0.0619140898594084 -0.02825379675950861 0 +-0.1521641403687932 -0.09085500083660938 0 +-0.05713964279977787 -0.06051772329618741 0 +-0.1166191182746996 0.0394216594440755 0 +-0.03224954249595552 -0.06875949581799146 0 +-0.03045925247174572 -0.07183947214600803 0 +-0.06010667757107306 0.01555855156973736 0 +-0.1485106028820966 -0.02129426095108252 0 +-0.04943443654053925 -0.0761017071788738 0 +-0.1570494360931293 0.04787673973831802 0 +-0.06266985576477574 0.08495144492522513 0 +-0.02296195927457824 -0.0810654316357584 0 +-0.05342873490443147 0.08248184242837374 0 +-0.0714892848414565 -0.07214252121467457 0 +-0.145473075665702 0.006815413687165191 0 +-0.1323761556445544 0.09713150261946489 0 +-0.02762520378891573 0.09712401133093815 0 +-0.02875464367466367 -0.09176198464844076 0 +-0.0506953161615697 0.005419888765436836 0 +-0.05422091662710337 0.05021544230799802 0 +-0.08260118353185822 0.07509589187652935 0 +-0.08228690385000516 -0.04099868894848759 0 +-0.1455111674863385 -0.09071172119061066 0 +-0.1280549584077894 -0.06359319948209988 0 +-0.0410445216891505 0.07929501270985398 0 +-0.03498825008019126 0.013329022634348 0 +-0.147390090869811 0.02742036667354215 0 +-0.007941970514875985 0.05256711509954629 0 +-0.09778670699855922 -0.01123052757150688 0 +-0.1272902715671112 -0.005669630460484801 0 +-0.01834085026440387 0.04759213104935392 0 +-0.07063338459267891 0.0911690899990015 0 +-0.09919643146489364 -0.05584446158240626 0 +-0.02068850000720784 0.03202375187242428 0 +-0.1267678684951327 -0.05736350400948766 0 +-0.1185735861594694 -0.06322162127892564 0 +-0.01711835826613455 0.02639034901594215 0 +-0.1128910880809443 0.003709777565680739 0 +-0.03339883225893962 -0.006065192487582072 0 +-0.1029090457605306 0.03325040724211342 0 +-0.096782383158937 0.04845367223202676 0 +-0.1176802077445142 -0.05085309988536067 0 +-0.08382682924250306 0.04646257803819798 0 +-0.05762698552164836 0.04988132438759471 0 +-0.1234267387580863 -0.07876033767358884 0 +-0.02722963945069973 -0.07661513148848362 0 +-0.1131725954745912 -0.07923973095566249 0 +-0.007655939575537491 -0.04328995163288115 0 +-0.1229853197375631 -0.04141626575334056 0 +-0.03027850207152522 -0.04006188722944599 0 +-0.1101838905650318 0.02126382573953058 0 +-0.01871685691320188 0.03454055153945661 0 +-0.03733772903330007 -0.07378717361679442 0 +-0.1334959522851113 -0.07898666475820731 0 +-0.1367707064530009 -0.08093436416737694 0 +-0.087440710990782 0.07822021388981659 0 +-0.1120053628980705 0.06082510670314477 0 +-0.1243173236422876 -0.04790755093360498 0 +-0.1036949148960016 0.08924259090140524 0 +-0.1099562477071908 -0.03962258450230778 0 +-0.027014407796889 -0.09707999873716247 0 +-0.1122660185418474 0.0464778691936472 0 +-0.07712628474606736 -0.03668315527489416 0 +-0.03794353929474365 -0.05781796420843169 0 +-0.08177158744649927 0.08673146585482172 0 +-0.05896081914850584 -0.05746091386312376 0 +-0.1262539624702242 -0.08418425111195456 0 +-0.05730521067151137 -0.09238934553953265 0 +-0.152039369396464 -0.01072688433763379 0 +-0.01557965483084535 0.01899310117864357 0 +-0.08971542976821142 0.04792800851073065 0 +-0.09170386955193963 -0.0811603131543186 0 +-0.09948622567731588 -0.07619329964840002 0 +-0.03564269916716178 0.07624850970532035 0 +-0.06404998544243812 0.0391973918275676 0 +-0.09038944534430066 0.02042437899200576 0 +0.07975521521851579 0.007710741070624551 0 +0.1036556603773586 -0.04365566037735851 0 +0.0525166547313662 -0.03447951531285239 0 +0.05082302918367058 0.04895190633212685 0 +0.1096947421585805 0.04902176303750735 0 +0.1199221462062071 -0.004921594575104091 0 +0.04043362370202555 0.002225618404403174 0 +0.0743892361677494 -0.0638611323086518 0 +0.03396170513267344 -0.06516661163989301 0 +0.07974475456696684 0.06639108626899774 0 +0.126462066570189 -0.06737232361098285 0 +0.12926248101617 0.02491114463399003 0 +0.08017866743052302 -0.02353118839109906 0 +0.02921264165531667 0.07117718592399323 0 +0.1297155561458374 0.07096937648966566 0 +0.08222974130994579 0.03684082689440347 0 +0.1309210180434217 -0.03147851216716224 0 +0.02927898017003878 0.02900594604153786 0 +0.0274617713054251 -0.02243940814398267 0 +0.1002871561228069 -0.07313652349433761 0 +0.05784313193805236 0.02305155507747059 0 +0.1034787024231199 0.02044193432409452 0 +0.05554502395335867 0.0740155673222751 0 +0.1043300759710853 0.07435425076319219 0 +0.1361798819039967 0.04706378620664173 0 +0.06208517484371043 -0.007455274657081162 0 +0.05442222347387626 -0.07674582916987524 0 +0.02323449362686951 -0.04516071263152437 0 +0.09600708350858952 -0.007511246272514767 0 +0.02209315031400735 0.04923413518006093 0 +0.1383814822388224 0.004855280863056338 0 +0.08308106359647224 -0.0443285738354855 0 +0.02077083409876114 0.009854445892158663 0 +0.1095166510444286 -0.02388432453166572 0 +0.1399396173488949 -0.05091583234379161 0 +0.05575722020556347 -0.05643173678729429 0 +0.02025592385655525 -0.08088993769520542 0 +0.1391453408208078 -0.01556361535995157 0 +0.1407535224115281 -0.0802172749233858 0 +0.08331976170174071 -0.08108659182436537 0 +0.04550166881626452 -0.01846308506817524 0 +0.06957308104543751 0.05059121221241051 0 +0.1201419267478637 -0.04956515321834899 0 +0.1159983159578973 -0.08238703684163351 0 +0.01787136259553485 -0.008643503101362424 0 +0.09147098327617946 0.05237570912160844 0 +0.08825085882125765 0.08231246161938813 0 +0.0173788418331994 0.08262115816680064 0 +0.1426211581668007 0.08262115816680064 0 +0.0389763761971131 -0.08275232970650651 0 +0.01724161303625133 -0.06210723579952973 0 +0.03996376346378031 -0.0493267247224565 0 +0.07198365430964167 0.08292089802073963 0 +0.1163466072831833 0.0116522852347165 0 +0.11893011893293 0.08282083420859049 0 +0.04107940601789838 0.08293954346195181 0 +0.09431002292315327 -0.05704833999240892 0 +0.1131075965817956 0.03175739651039706 0 +0.1434210676628043 0.03201439975353938 0 +0.06849883758988286 -0.03569337317197875 0 +0.04223338264526636 0.01847694207694011 0 +0.07369768310356245 0.02258473969379136 0 +0.1441183694218561 0.06178756004967847 0 +0.0550801755262661 0.006656632906087548 0 +0.04468090109521632 0.03422741903070205 0 +0.0941951888897104 -0.0310743289310461 0 +0.09900809454672105 0.03664445072852085 0 +0.115665098722222 0.06411095528291846 0 +0.04447216755492818 0.06416908998555697 0 +0.1095903130143544 -0.05951958250807699 0 +0.07755763223972814 -0.007997582168365122 0 +0.01547510698891378 0.0641504299529809 0 +0.1450499853359895 -0.06497077154214854 0 +0.06803640750527047 -0.0846003726382822 0 +0.01571872544740693 -0.03233295123156547 0 +0.01491696808285822 0.03593999791347261 0 +0.06111058183812595 0.03808005138677463 0 +0.09518501504948208 0.007239414362145649 0 +0.1447637566709885 -0.03639915531113751 0 +0.05999744376517914 -0.02366502929707864 0 +0.03731744629151322 -0.03436450430754135 0 +0.03612020632617111 0.04540175837460621 0 +0.1238453022815533 -0.01940969222098585 0 +0.1453545030563671 0.01761241096343308 0 +0.06904363618580983 -0.05004953894228599 0 +0.08905962434636663 0.02401581823382594 0 +0.05870801760984611 0.06054465713293616 0 +0.1175686822108702 -0.03535369715728492 0 +0.03192935490069659 -0.009485255297491925 0 +0.1224148356696493 0.04420035396537701 0 +0.09633847577932947 -0.08611005476217702 0 +0.0137605636529212 0.02200710708006353 0 +0.1026275702627889 0.06046141986964236 0 +0.1076197698549228 0.0017834999425063 0 +0.1288258489601159 -0.0864137004016402 0 +0.1272756049236563 0.05696711939676229 0 +0.1005462393402339 0.08599468414781593 0 +0.08688412395782565 -0.06848743252345767 0 +0.0585922607179659 0.08704926166084002 0 +0.04717047616724435 -0.0664488860171345 0 +0.06661008948982475 0.01205888407463078 0 +0.09247680423763817 0.06935379211959233 0 +0.01299954571463783 -0.01891878678657748 0 +0.06782497556543364 0.07023448395393446 0 +0.1470312691167305 -0.004300862006984618 0 +0.1310280985181846 0.08777918923417366 0 +0.028941691966643 0.08770108291080467 0 +0.1310818796169494 -0.005854566436587815 0 +0.04945166865839441 -0.006455483737390202 0 +0.03103223659634097 0.05814724137006252 0 +0.06231854862033534 -0.06724154456030258 0 +0.1473344984274272 -0.02544210185531015 0 +0.1082026075461665 -0.01257848363073628 0 +0.04952322166386355 -0.0875221908981911 0 +0.1468541956031564 0.04326720008423202 0 +0.01258737628813401 -0.05084638516087371 0 +0.09108157439118203 -0.01911527341168317 0 +0.131275946871046 0.03633054119644178 0 +0.01234785503149852 0.003360268325604891 0 +0.1152635347860362 -0.0701806817003799 0 +0.1283442449348173 0.01185249798474517 0 +0.1476707590005567 0.07254798687560265 0 +0.01252032206230899 -0.08791034499727877 0 +0.03236570965952896 0.01106192535738423 0 +0.0282673500134835 -0.08856265564546507 0 +0.01149398202355725 -0.07253976143958657 0 +0.02975612174071551 -0.05487155358491924 0 +0.07108868122500532 -0.01813245334977711 0 +0.08049908374136586 0.05467874852090673 0 +0.08636795928038456 -0.002706336720779547 0 +0.06953477425993287 0.0004144414263323143 0 +0.08262502706795757 -0.05606163990596923 0 +0.1073653167437593 -0.0884579720798381 0 +0.1487166006598883 -0.0888024101003594 0 +0.0118079443146853 0.05345245870121234 0 +0.1315342906004607 -0.04332595982204362 0 +0.02746371586629536 0.0008853695012070964 0 +0.07075653047488153 0.0330925096818119 0 +0.05881547595443253 -0.04557416878941521 0 +0.02617466406919124 -0.03633588571131429 0 +0.1485714680421941 0.007493656012648256 0 +0.1301054060815704 -0.05671785916607278 0 +0.02784104943746021 0.0409876587474397 0 +0.1141316286474142 0.02237602083639832 0 +0.08427298424434097 -0.03370784399225443 0 +0.09301999276065237 -0.04157993963765347 0 +0.0740064668292726 -0.07525637670936564 0 +0.07953076989575593 0.08879415728726434 0 +0.01085816029409448 0.07386511308020151 0 +0.0312209106235663 -0.07535046813589416 0 +0.1499105896668444 -0.05641078534964742 0 +0.1105112026777533 0.08937207494933119 0 +0.149469993262072 -0.07487775213502966 0 +0.07617210564131383 -0.0901765327092878 0 +0.02386860092263489 0.01979900186281141 0 +0.1252445822921396 0.002550368156193107 0 +0.1048353574426156 -0.0334226461364661 0 +0.07935467658571835 0.07662713599909832 0 +0.1314217818035951 -0.07587600201711391 0 +0.1191133003247504 -0.05840447950345294 0 +0.120264006557829 0.07280391103833193 0 +0.03973599344217095 0.07280391103833195 0 +0.04823517172004865 0.09060138122625749 0 +0.009497410297685447 0.01235892366152885 0 +0.07299727030024136 0.06073684025526738 0 +0.1335750957849992 -0.02261957713807829 0 +0.01025264007110739 -0.04080634517318463 0 +0.01017963339621346 0.08982036660378663 0 +0.1501335681674258 0.09023793628223849 0 +0.05972840565630964 -0.08940932366357829 0 +0.150148710611942 0.05338048697618195 0 +0.03778047048611927 -0.02425715566753777 0 +0.1501426220935699 -0.04635681449169794 0 +0.118364897946286 0.05343770000696201 0 +0.1500853111376606 -0.01381903915925819 0 +0.08628178667215698 -0.08952952356469497 0 +0.1374789181080218 -0.09025518818373357 0 +0.08833047535383257 0.01415573095068687 0 +0.1112572751454632 -0.0500146154866228 0 +0.1019652626636947 -0.01877566779524486 0 +0.1076510221066656 0.01183214032074177 0 +0.09089833474749176 0.04242131381139456 0 +0.09928272435654845 0.04640891014109767 0 +0.009340195595478603 0.04404978085057863 0 +0.05113792866326369 0.01568592767391531 0 +0.0461350375273558 -0.0274583080216999 0 +0.03312564128758312 -0.04377516077692244 0 +0.04127762120991067 -0.05932748667799095 0 +0.02054746609745491 0.07292064178692692 0 +0.06140394228365709 0.0475552133896921 0 +0.0431047053800068 0.05376781034259671 0 +0.07730659290009909 0.04546897153080582 0 +0.04126214040918794 -0.07346398408762032 0 +0.02172909288560585 -0.07113145441088814 0 +0.1387791323575888 0.0238040587257807 0 +0.1048527000543584 0.02986281354697691 0 +0.05455863867526953 -0.01398837661928086 0 +0.04820543394484299 0.02501917113303732 0 +0.04899494337829972 -0.0455289018627227 0 +0.1029450060457918 -0.05253438233289232 0 +0.1500394930234352 0.02596784752086078 0 +0.09216086409862026 -0.07755541494609032 0 +0.1390118537368207 0.0738271760982203 0 +0.1207768735834226 -0.09139492544698442 0 +0.1066996945736655 -0.07920539932917806 0 +0.1073626660708035 0.03993033791503452 0 +0.08791754785955493 0.06110505794687333 0 +0.09212857766442978 0.09157957617788699 0 +0.03878175910998058 0.02724201209191081 0 +0.06463503378360133 -0.07570034254748387 0 +0.07132932718152815 -0.02644959125265383 0 +0.100839987008795 -0.06375155305946162 0 +0.0527137345824352 0.04009791385063149 0 +0.04089506229615228 -0.01094094443998604 0 +0.1395798969539166 -0.02941492725204355 0 +0.009234535068903297 -0.0109944126156913 0 +0.08640792693976976 -0.010811716626683 0 +0.03522986360565532 0.0363575851461741 0 +0.06650452042457269 0.09100338915617984 0 +0.1266683772267953 0.07916401829194546 0 +0.03327044765274746 0.07928302402536504 0 +0.02114909099287124 -0.01702639753337033 0 +0.06605650549599643 -0.05931737049754774 0 +0.1231227728886268 0.03186032323371585 0 +0.1355480632632825 -0.06322754313412671 0 +0.09050913357182523 0.03259277698130933 0 +0.06025326549582904 -0.03247335383701447 0 +0.1181563756144487 -0.0268734398734858 0 +0.06627067335678583 0.02652161468797029 0 +0.01995716685499657 0.0908000848122418 0 +0.1400290025086904 0.09088322312257013 0 +0.123010002396107 0.09102782789199892 0 +0.03695222538026623 0.09101912737927362 0 +0.1348308907585666 0.06357440080828707 0 +0.01947598620671081 0.0277604737066448 0 +0.0960120648951799 0.07749198027718988 0 +0.009083560736668677 0.02909295249493206 0 +0.04164832030782574 -0.0917207091259456 0 +0.05556837251952492 0.03175838550242046 0 +0.04993222061207435 0.08079382350445724 0 +0.03271016724700881 0.02053589718030131 0 +0.008846279974265285 -0.05916405482075599 0 +0.04418305028880451 0.00986932498690023 0 +0.0737867240300796 -0.04260379795400767 0 +0.1222414915045902 -0.0744739743960925 0 +0.02446558341664012 0.06403399061684688 0 +0.1102735976879196 0.08024638625412557 0 +0.08094694392172042 0.02816315247635371 0 +0.1520688822245547 0.08036673225027147 0 +0.05276690601563637 0.06615078532734581 0 +0.1166967066002322 -0.0140523400666196 0 +0.0894323599051402 -0.0491930004800029 0 +0.02049901992143102 -0.05433757316806006 0 +0.026072830569944 -0.06203578759299964 0 +0.02037924667462143 -0.09131132059097141 0 +0.1387806457891314 -0.0716023184869979 0 +0.1158487318342863 0.003073909360024959 0 +0.06297377975116766 0.07939164799289919 0 +0.04636945887536213 -0.07901925154656135 0 +0.1380849153387771 0.01379757849413099 0 +0.06845115809719152 0.04243382830936291 0 +0.1212800356402775 0.01968985858077701 0 +0.1519851051179678 0.03526347465629668 0 +0.008412426232012144 -0.02697146467688128 0 +0.008435057457248585 -0.0799835758164153 0 +0.09677225893710374 0.02640955343256145 0 +0.07941401927401447 0.01609121756286497 0 +0.1310394983087349 -0.0138118187232163 0 +0.05052918972620817 0.05775576338002522 0 +0.05961314204657828 0.01409905637864653 0 +0.04400440802481955 0.04274146353414596 0 +0.060985245686665 0.001183041325521832 0 +0.01981812901555638 -0.02478103540415373 0 +0.04863096167114751 0.001966974024955678 0 +0.1077922516506544 0.06629117043802171 0 +0.1101027781826934 0.05759100819809231 0 +0.09897253872958345 -8.517800315900784e-05 0 +0.1522674603760456 0.06467370747248655 0 +0.1394077052805668 0.03949037079881525 0 +0.09587759710746784 0.01558973268153782 0 +0.0476942660965662 -0.05389252900467133 0 +0.1518778395518617 -0.03199832593318495 0 +0.1415425484578157 0.05337858332776613 0 +0.008146338312197179 0.08174184236775282 0 +0.136871984409892 -0.03800578534613564 0 +0.1239898201051657 0.06433291163595671 0 +0.1077115128447583 -0.06796998218064426 0 +0.03590277157691948 0.06483228572411662 0 +0.04383554153944752 -0.03860814273962027 0 +0.1249607990428529 -0.03795286265859384 0 +0.1395404536853043 -0.006853788226919511 0 +0.1115183231161003 -0.04193803505741549 0 +0.08782641042326836 -0.02643243228716324 0 +0.007859078865416256 0.06089153452800802 0 +0.03357752562039472 -0.01737717554894455 0 +0.02002080815895747 0.0005612332772129801 0 +0.04779469222147573 0.07263627141591418 0 +0.0762646500352064 -0.03281877136280819 0 +0.1523152374905994 -0.06735933370760881 0 +0.07431683125475894 -0.05600788283027719 0 +0.1285546305233959 0.04930479375927321 0 +0.02491153511528777 0.08009205554797974 0 +0.06972014892958396 -0.009252889869166966 0 +0.07759650150640643 -6.246220635919466e-05 0 +0.0794139022579175 -0.01474249913138662 0 +0.06760891437679688 -0.09233117616828793 0 +0.05454968882889797 -0.0655934069806795 0 +0.1351136547711946 0.08068018976457411 0 +0.01790064265371205 -0.03907097905427481 0 +0.1147378339953167 0.04374295542745557 0 +0.05253299292017991 -0.02226131944802274 0 +0.0662009415588992 -0.04287791856917315 0 +0.0189742800099128 0.05670956688778772 0 +0.01806872517746905 0.04321864395663891 0 +0.141394433922181 -0.05844285096429316 0 +0.06590570575150755 0.01899854834537521 0 +0.1125070164691698 0.07298026596042376 0 +0.0296130482446241 0.05032829305145147 0 +0.08494622859876283 0.04797957621866727 0 +0.1526814630187795 -0.08202731756392362 0 +0.1020844657400258 -0.0260577915721311 0 +0.08728063552349566 0.07488219383283075 0 +0.06026907842197649 0.06888112959295783 0 +0.1524178751064207 0.01333378954472091 0 +0.06255879371807858 -0.01553663060142169 0 +0.08760965265451265 0.006093443989766287 0 +0.1113651289408908 -0.004684666397788972 0 +0.1001735043276674 -0.09196657198777715 0 +0.09431435852906508 -0.06789920632512265 0 +0.09953459480654561 0.06854804112500085 0 +0.0814318119826353 -0.07374871465309804 0 +0.03168169789901374 -0.02935172729853191 0 +0.09712246986938275 -0.04771287358471318 0 +0.125619129526354 -0.02633739413676135 0 +0.06039306239820187 -0.08189010664765925 0 +0.1418614749751994 -0.04394544223098898 0 +0.007208524244091146 -0.003663683883061478 0 +0.123524575173382 -0.01161595128689225 0 +0.09862361324781027 0.05429166063217227 0 +0.007453308129708045 0.03676136068296176 0 +0.0250774476484912 -0.006157748160164402 0 +0.07599873299014441 -0.08242761684185232 0 +0.03425882520848375 -0.002670036050519193 0 +0.069551054946555 -0.06892636285021474 0 +0.134332385679611 0.0542173433368375 0 +0.06182386510918179 -0.05221739728606374 0 +0.0634431268361958 0.05475000983865393 0 +0.03415984754871336 -0.09237510048813244 0 +0.1123354187488767 -0.03054922454905129 0 +0.1517908124183372 0.0005299450077253857 0 +0.08793844468898304 -0.06172031849785246 0 +0.007046392606940545 -0.03439556601519245 0 +0.1408008707449057 -0.02221328902854597 0 +0.1362200141233985 0.0308547762242356 0 +0.09506048848099319 0.06254136553686199 0 +0.1041745860188957 -0.005496373866515079 0 +0.007528574905112386 -0.06618330388104382 0 +0.1530614311167685 -0.03935246697029648 0 +0.11311784784254 -0.09318998020192858 0 +0.007149080343057848 0.01916069267117858 0 +0.09916012799199085 -0.03785562598190074 0 +0.07673360978024116 -0.04887992934745659 0 +0.1023401257429925 0.006703501889604291 0 +0.09959253960437985 -0.08019961592637881 0 +0.1192792022154649 0.03784309809009037 0 +0.1328523971799509 0.01867138396738506 0 +0.1043582011058759 0.09287184925740075 0 +0.07291003671094227 0.006600148003255109 0 +0.07375903573647283 0.09297601295259804 0 +0.006924408517890512 0.06757293166297755 0 +0.1185604886685599 -0.04283241450869547 0 +0.07231102819574427 0.07573723258729932 0 +0.01637059583878179 0.01563179486562529 0 +0.1316620243077302 -0.09281015956152858 0 +0.1201534577525928 0.02493772153786109 0 +0.1533854679217143 -0.007640782308384414 0 +0.1529768355456852 -0.02022323783522267 0 +0.02236412992794576 0.03501735556071889 0 +0.05632238901127459 0.0536064754158455 0 +0.1232423691138267 -0.0823121990774721 0 +0.05452304957727905 0.09333603555391141 0 +0.1323560011962777 0.0009132044537557075 0 +0.006970061990757227 -0.09307789631990215 0 +0.09372381774119534 -0.09301715313279951 0 +0.04856317383842766 -0.07202468659849319 0 +0.05449808252737856 -0.001603598431979261 0 +0.08536722117415797 0.09309098103348626 0 +0.1536938524434958 0.04748628387755171 0 +0.08136219690437246 -0.06400707766646825 0 +0.006973070127551053 -0.04660248835065713 0 +0.1430893870229295 0.06768506292497642 0 +0.02669204915468262 -0.08171084981694819 0 +0.06016414044884168 -0.03842249344097369 0 +0.05373631575351282 -0.09346886021927955 0 +0.05399985793377907 -0.02924442481701899 0 +0.1443908410164421 0.001969253656339314 0 +0.06279495438691646 0.00639460650848309 0 +0.0893932789902003 -0.08447417678806671 0 +0.006770410351983626 -0.01782101704185627 0 +0.07261842737122658 0.01610919742802794 0 +0.133322341712461 -0.08342839831801871 0 +0.116248302403765 0.09332710892578755 0 +0.1308163213353798 0.04290707960130664 0 +0.1283970388261101 -0.05021812433152132 0 +0.04372399169967704 -0.004354428601893981 0 +0.06538263143712736 0.0637011969032328 0 +0.1144501038789084 -0.02163117079977252 0 +0.07633182228592106 0.03893493727103364 0 +0.02643504816679634 0.01480775459599657 0 +0.006672101975187239 0.007165502375635104 0 +0.03379400644664671 0.004524287911682853 0 +0.1031697820349272 0.08198784640607748 0 +0.1531559470629109 -0.09392216569210443 0 +0.1441884969547151 -0.09387666840608537 0 +0.0285476972267164 -0.06922602344150668 0 +0.1128563226426155 -0.07603342644149301 0 +0.02779976825873332 0.09338691724137732 0 +0.1322047341949588 0.09340655947721022 0 +0.07949572018560636 -0.03893798396833335 0 +0.1234484778632462 0.008451304290818891 0 +0.05419755420612694 -0.05022936681297929 0 +0.09678250391223771 0.09347982138055436 0 +0.03586932556561847 0.05301718813543484 0 +0.04912271749623563 -0.05855459781485593 0 +0.1529733663970178 -0.06052703466496134 0 +0.1449093005236561 0.009867823171471148 0 +0.09453273558416088 0.08359948740320411 0 +0.05646903595051621 0.08082702622585305 0 +0.07762379701719439 0.08310756920320571 0 +0.01598951504715539 -0.04699945367935034 0 +0.07377479018575493 0.06682611366115136 0 +0.02958571581772925 -0.04837109433673825 0 +0.09424585461450033 0.00188858291669008 0 +0.04338781045577623 0.09364781788788451 0 +0.1243342707644326 -0.00305617589443114 0 +0.1160456687632671 -0.05515283055211023 0 +0.05721367137520025 -0.06925027834190212 0 +0.06551564505732287 -0.02778426968862779 0 +0.02771762264898308 -0.01448290967159713 0 +0.04185814092317258 -0.06503205137966751 0 +0.09580359215706526 -0.01445175649632364 0 +0.0949629687868174 -0.02340774750311999 0 +0.06022759096095133 -0.05974661485701539 0 +0.15360991895684 -0.05110386034618253 0 +0.02678753288393827 0.005829973721455457 0 +0.04654194756399305 -0.09401295886338222 0 +0.04005502657192435 -0.04180786305356302 0 +0.01471903544245906 0.008026362495474473 0 +0.08170197708454802 0.02197899804785995 0 +0.08634590680040716 0.06735810605457013 0 +0.08586612043736948 -0.04030865499864602 0 +0.1222439860799843 -0.03258617102472415 0 +0.01433976671326008 -0.01309338887435519 0 +0.1138603898556326 -0.06329767755122222 0 +0.1210108816240581 -0.06682315253705619 0 +0.1311595119988115 -0.07046424914820715 0 +0.02713349894538241 0.05516928858951803 0 +0.007066100585811823 0.04872738950507278 0 +0.02389567598590225 -0.02824438510784692 0 +0.006118947244198513 -0.05391250719449092 0 +0.06102284949504067 0.03099322268242361 0 +0.1537723382475641 0.05850564510969105 0 +0.03392693479780399 -0.06003933673144515 0 +0.1423081741322869 0.04759351686063173 0 +0.04884674096842226 -0.01398742620784461 0 +0.05629928837277991 -0.008747634192621232 0 +0.039768459141651 -0.0163350554984615 0 +0.08269269013611175 -0.09485526167244684 0 +0.1085348456339847 0.01770787958260817 0 +0.03816150603334723 0.05846408947734132 0 +0.112380323111143 0.007877103076645941 0 +0.1536583228481081 0.02013237042045227 0 +0.125944785846183 0.08567039422025197 0 +0.03393049741753409 0.08564594404258068 0 +0.06121503091413422 0.09378116717605198 0 +0.1108099633763231 0.02617889851034404 0 +0.03863576623302372 0.01178127872607709 0 +0.1073363252451147 -0.01834873016926527 0 +0.1455717543253177 -0.01090919198192677 0 +0.1467791280439316 -0.01800169268206852 0 +0.05316947158084335 -0.08402949069921595 0 +0.1450276636304063 0.09350760522709434 0 +0.01495431302306175 0.09334656241111201 0 +0.1250071447766444 0.0399366964914292 0 +0.08499292911594686 -0.01941388761406405 0 +0.1443026906349321 0.02546338281756116 0 +0.1457239518666285 -0.05034864257360235 0 +0.1014101766584555 -0.01202717003447298 0 +0.01441733246712502 -0.08264414162558782 0 +0.122110337081876 0.0587559184187128 0 +0.1048424973843222 0.05359370047081712 0 +0.1251949372394686 -0.09374597980142228 0 +0.07307809492141797 0.05406652954414534 0 +0.07825848125663476 0.06118283287844103 0 +0.1242242829992578 -0.0549532242064934 0 +0.09190206466279652 -0.03512232416931352 0 +0.04304562180060873 0.07795524077549544 0 +0.1457898626699447 -0.03084878202431301 0 +0.1539674105825376 0.04074936914005058 0 +0.1247518692937291 -0.04443146257119356 0 +0.1444520163090884 -0.08692477886157386 0 +0.01643327544747615 -0.06690215009298184 0 +0.01728606003089219 -0.07481141855395743 0 +0.01501521497585969 0.05004039031614931 0 +0.1318734265202309 0.007982912807290268 0 +0.01434249742069971 -0.09386888740961591 0 +0.06432905666117565 0.08535995101582707 0 +0.1007388269616688 0.01297602050862795 0 +0.01415899046817892 -0.004471052170436389 0 +0.1261215175944865 -0.06080952206396925 0 +0.1445384608581138 0.03792163541838307 0 +0.03140899731103113 -0.0845337694653978 0 +0.0154613094180849 -0.05491180920518808 0 +0.1533078725214264 0.07590116990756555 0 +0.006026584835476391 -0.08552124911407334 0 +0.04429730900884996 -0.08544534932389525 0 +0.02588225418589846 -0.09315563999665265 0 +0.1547014739409896 -0.02602399275206965 0 +0.0670677369360851 -0.021222942819519 0 +0.1360559855490603 0.06728714714649391 0 +0.09060586845738815 -0.006423625252845043 0 +0.1439449107932162 0.07683457609217374 0 +0.1282730372111965 0.02948706943700204 0 +0.1358238807997556 -0.05558662316975169 0 +0.03668652344785273 -0.05252042838338831 0 +0.103378593602708 -0.08589787317518212 0 +0.1125601796108013 -0.08611400866890939 0 +0.01540778655765344 0.06998881394619735 0 +0.006049012642082898 -0.07474470097775264 0 +0.07678021669871916 -0.06987828313873114 0 +0.1462709921524656 -0.07975570072288646 0 +0.03441864696020071 -0.0723194914384937 0 +0.0722651923817267 -0.09482956356158552 0 +0.02202812015534179 -0.0849100371821606 0 +0.09384018850825077 0.0211487123096379 0 +0.07474877889033368 0.02899243154411494 0 +0.02645976836203906 -0.04089572221773091 0 +0.0318331182924325 -0.03686469453715167 0 +0.1340266523242843 -0.04830629099721279 0 +0.041031677642989 -0.02913802847672593 0 +0.0862383250789623 0.05533358199877255 0 +0.05018484300584185 0.009803481274985107 0 +0.1540671037678548 0.09406710376785471 0 +0.005932896232145276 0.09406710376785475 0 +0.1372458036121941 -0.0008258786534850893 0 +0.1175095183318213 0.0776575125642823 0 +0.0332158606810828 0.04131711995353337 0 +0.07519883722579933 -0.02199741509841543 0 +0.1543878251248769 -0.08671174180007088 0 +0.136197677296723 -0.0112649994263614 0 +0.04502832048617032 0.04826875528727714 0 +0.1445840066821535 -0.07153127974745603 0 +0.08736894131514739 -0.05413237116174142 0 +0.08403709676688648 -0.0512943501195561 0 +0.1537942827122392 0.08545589197750639 0 +0.05301909256280862 -0.0425266958675436 0 +0.1532500946722869 0.02963062906997002 0 +0.05459388953209186 0.04482858672453701 0 +0.08265268049895676 -0.006456468154483849 0 +0.06386866237461368 0.07318049588438991 0 +0.01554423302933609 0.07743246156152128 0 +0.08246819273483424 -0.08641532296539596 0 +0.03030079732075803 0.06373081742040224 0 +0.08530990271886792 0.04266295967946011 0 +0.0746371264137414 -0.01345477404287792 0 +0.06935382965026439 -0.07882849331223177 0 +0.08772398566142509 -0.07500366520742222 0 +0.02373135211288719 0.08572313648977173 0 +0.08507169605265837 0.08729309401220975 0 +0.01447143428562499 0.02792304666402856 0 +0.1096433353102046 -0.03676678206024917 0 +0.123372182110891 0.04969325645871412 0 +0.02422494630281263 -0.07582232028520561 0 +0.107853786105829 -0.0944755447467176 0 +0.03567757774161938 -0.07763109723793073 0 +0.005540055755825513 0.07731405204067764 0 +0.05291115779211788 0.08579720971713467 0 +0.005781741431390119 0.05560611328557451 0 +0.02604528584943595 0.04576199010073235 0 +0.03006670421769312 0.0336105836190381 0 +0.08281645593714917 0.002984690500212021 0 +0.1333649461007559 0.07506791514807513 0 +0.005968345067303711 0.02456652731093716 0 +0.1547623472250573 -0.07258299083876527 0 +0.06698064662131183 -0.004371123437214896 0 +0.07318605140087661 -0.004305428883266926 0 +0.07721922548638961 0.07127011315784294 0 +0.1017757767016247 0.04129145789598269 0 +0.1560450709426772 0.007441394817316584 0 +0.1385952821914148 0.05844989035939337 0 +0.08076168615226911 -0.02945994493437507 0 +0.09386983944722675 0.04715530349119633 0 +0.1139697366489636 0.01712361209956527 0 +0.02438583575251898 0.06922502499450639 0 +0.0654173453520684 0.03483040431676025 0 +0.04345491009075141 -0.02358289456183733 0 +0.1059299000427925 -0.07369371876327829 0 +0.05231041732316117 0.02119711296343431 0 +0.0758964911425957 0.01145072816425772 0 +0.01558311003827808 0.08802463480886528 0 +0.1444168899617221 0.08802463480886512 0 +0.01412915467919107 -0.02717097085980207 0 +0.06236582633892748 -0.09435295815581095 0 +0.02042626949009337 -0.03465020396957517 0 +0.1078392883005274 0.03422455289835871 0 +0.00527947987461931 0.08664862441969756 0 +0.01452483269649692 0.05862882193098256 0 +0.1147067831351795 0.04901878954648907 0 +0.03870318856105684 0.04080225853137742 0 +0.1035252683522076 -0.05823899217260243 0 +0.025479954763716 0.07510204606686467 0 +0.1311589885902699 -0.0378921956130855 0 +0.04962265501399697 0.03022438680188058 0 +0.04695777772250509 -0.03449349905826353 0 +0.1543710628433964 0.06947046469524086 0 +0.02854827114714448 0.02345375743726569 0 +0.1062866293444532 0.08624509725203812 0 +0.1362293751706306 0.08602788023414426 0 +0.07782099746959913 0.03356344259884302 0 +0.07424617067256507 0.08713636651844897 0 +0.1296790743511246 0.06462619728866788 0 +0.09934059907555207 0.03069536473779203 0 +0.1274076789230049 0.0177215340818565 0 +0.1155988209787977 0.08784014868603009 0 +0.08794384642166442 0.03756642659208747 0 +0.1075301359002034 -0.05395093809648781 0 +0.07161564469255779 -0.08867890176722718 0 +0.04353345036787058 0.08800287547339232 0 +0.1058019257100289 -0.04881300867901198 0 +0.082898469246552 0.08115421776333878 0 +0.1267803174719759 -0.07263827445614549 0 +0.04308981245246762 0.02346093313060355 0 +0.0325149394431886 0.0954237131758728 0 +0.127480307732535 0.09542776213995253 0 +0.1400730455309802 0.01858517372013558 0 +0.07798384552955259 -0.06000214983042293 0 +0.03469101180248317 -0.04821008892549108 0 +0.01891398557904414 0.02251590843688272 0 +0.1341928603878337 -0.02802708333666386 0 +0.1255308456391529 0.07327843942542199 0 +0.03827856031875878 0.07816850297845902 0 +0.03430800106781347 0.07338250037320887 0 +0.1484791334208148 -0.06110766864631642 0 +0.08510040970872579 0.03196497671106664 0 +0.03883754826918173 0.006379865377091152 0 +0.1161777823086833 0.06936566045982637 0 +0.0682146399669234 0.0558869771362577 0 +0.09651882757477333 0.04230575169038854 0 +0.07813052065632559 0.09463450225435498 0 +0.1347522921251512 -0.01729300430830967 0 +0.01203981443512121 -0.06366132901230853 0 +0.09316385584003514 -0.06207109694335408 0 +0.0362545921349732 -0.08743001475630893 0 +0.1204412324164316 0.0001186264603953497 0 +0.03668092505171991 -0.007287629603084052 0 +0.1366580915685473 -0.04342274742789404 0 +0.04401139288750355 0.06933987023025195 0 +0.06622033595491673 0.04662703198076834 0 +0.00497241583008298 0.001802835556713743 0 +0.09229795585314492 0.05780026159145054 0 +0.0672766111168159 -0.06445129733583943 0 +0.06818853197960462 0.005350614125655465 0 +0.02245143159394962 -0.01062674793517676 0 +0.112865415109898 -0.01002414489515907 0 +0.1123633611273514 0.03825259799581044 0 +0.00442255933064426 -0.02232474272244457 0 +0.1070073106046274 0.02302726792985303 0 +0.1365427887823627 -0.07716561405873053 0 +0.1487018718856734 0.03075426594497277 0 +0.04721542453903574 0.01968810414534703 0 +0.07237574929236837 0.04596110915106311 0 +0.09630344043407092 -0.05238261271860718 0 +0.03947688574129348 0.03228864352972604 0 +0.1479749494758247 0.05781739627897014 0 +0.1286688835441439 -0.08126390336589714 0 +0.1161152307494182 -0.04746453048034932 0 +0.0343797679332865 0.03067781856119159 0 +0.082596475626545 0.07121295392704662 0 +0.1219331631578621 0.07791017665801116 0 +0.03577214064927277 -0.01251004250165794 0 +0.1093164728249041 0.09447820236949329 0 +0.02186413458864739 0.005118076433394878 0 +0.1156676251614315 0.05890988322354341 0 +0.1293724833658527 -0.01958503110678923 0 +0.15527716451373 0.05250000000000003 0 +0.04297223498825832 -0.04576152200956719 0 +0.09326669538031256 0.03796043771600739 0 +0.15525886762052 -0.01259432372652662 0 +0.04397624122629966 0.02874376095297673 0 +0.09948549661584431 -0.03278422301521383 0 +0.106274515256536 -0.02812894024736649 0 +0.02215001110931163 0.04044152705544433 0 +0.08230475177852749 0.05881437473085053 0 +0.1340309118420432 0.02710068767631936 0 +0.09975681948343706 0.07333446402534213 0 +0.05351479997404253 0.02624627727096248 0 +0.03360274374335467 0.02547973205615083 0 +0.09192907475007681 -0.01160424633894615 0 +0.02191552405467106 -0.05939399092796733 0 +0.1048987751845871 -0.03861929969062172 0 +0.006047147997654876 -0.03923047942826297 0 +0.07703130317966088 0.05106802195416242 0 +0.0951197452965184 -0.07318294953619539 0 +0.004327148862742912 0.01200070185347169 0 +0.07344325841573375 -0.03720133885152867 0 +0.1048305348147096 0.04614279857442783 0 +0.004026439343402639 0.04224313070181279 0 +0.04778548973953454 0.0534027155376002 0 +0.04531578202270718 0.05874996982377704 0 +0.04211540701451097 -0.05399824049196864 0 +0.08293220915122686 0.0121033488552415 0 +0.02142620717496862 -0.06519662800562871 0 +0.1475610540178049 0.04867002283156884 0 +0.04904662951439179 0.04401421826325454 0 +0.05616355690674624 0.03662938666004353 0 +0.04107773558223409 -0.07771207776340971 0 +0.1037740725492836 0.03698519064528534 0 +0.0520150350966426 -0.06867515870088747 0 +0.054993066180368 0.01200522500375166 0 +0.154855038778143 -0.04399225939464716 0 +0.03787661128871823 0.0220782230562389 0 +0.02116154914917615 0.01439245468071415 0 +0.06455171753876111 -0.08843645914939799 0 +0.04757146618612157 0.09587023438127036 0 +0.1398942363754014 -0.06697597448811965 0 +0.06744254131880015 0.07691697663064818 0 +0.1024500987163837 0.02569154558309204 0 +0.0892902886687036 0.01868833206180324 0 +0.137624450262556 -0.09517961890332327 0 +0.09273192257352088 0.01123962736194649 0 +0.01322991190422501 -0.07692347505798469 0 +0.117051546908407 -0.09538770965911018 0 +0.03239634079733703 -0.02228363355775636 0 +0.00482394001059743 -0.007684664319089918 0 +0.06415857750132234 -0.04778225703850931 0 +0.004836521323878689 0.03277841097228364 0 +0.08749999999999993 -0.09547207576398183 0 +0.01364868823641575 -0.03687774367530903 0 +0.05456374363057039 -0.08883499349071194 0 +0.1548445670923592 -0.07795757386984557 0 +0.1462086788441006 -0.04143036633148008 0 +0.05376528498492926 0.06154592858977552 0 +0.1358635739561195 -0.03296571793813946 0 +0.01719224332166877 -0.08698021385568687 0 +0.09192878199462183 0.07446072402127395 0 +0.09189403609218803 0.02752077226637899 0 +0.0624307309797162 0.04272880237314165 0 +0.07875931647687426 -0.07806570470574969 0 +0.08863646532240847 -0.04378651962874974 0 +0.1046344609824021 -0.02233054821537701 0 +0.1237310812060011 0.01417977249978881 0 +0.09812058190328121 -0.05974770022465416 0 +0.1556058925980746 -0.05592361339346522 0 +0.0473996188212175 0.03909294527676317 0 +0.1301645973313898 -0.06085155137970257 0 +0.02265136768542689 -0.02110667696458973 0 +0.01820670871882478 -0.02015838036732055 0 +0.01703238289582725 -0.051180491204932 0 +0.1057045635326464 -0.06343586119718612 0 +0.1396412923611852 0.06427058590221039 0 +0.1484489409179416 0.08491950133236205 0 +0.1111461237284288 0.06246405839192035 0 +0.04412125560231499 0.004635798109362405 0 +0.1117733436267893 -0.01526411670233544 0 +0.05641135875792728 -0.01978845124563145 0 +0.05117629314396292 -0.01816909682943242 0 +0.1488762520438013 -0.09425307905959185 0 +0.1407295846357345 -0.03433839300317612 0 +0.04921585178959632 -0.03997147715600349 0 +0.1439699877585713 -0.07641559517207627 0 +0.0581073534165081 -0.02767088355551676 0 +0.1332610627722831 -0.08881118337942683 0 +0.06260917853153283 0.02281981834437025 0 +0.114641309420394 -0.05887784388054193 0 +0.111462725385074 -0.08028279179576583 0 +0.01978976020189752 0.06701992183680101 0 +0.01123622462867455 0.03899057452755396 0 +0.0760115935241911 -0.02735376733055231 0 +0.04589213363269285 -0.06179670991183923 0 +0.010877037576772 -0.04586606972381056 0 +0.127974920861104 -0.009925993750831853 0 +0.05608959606208926 0.0180389086146063 0 +0.004612463609372886 -0.06229221984065972 0 +0.04913555145866867 0.06257672431779274 0 +0.1029044842815753 -0.06841873680996158 0 +0.03785484497570718 -0.09542280201820837 0 +0.01258666009471533 0.08402870253856123 0 +0.1186369108422234 0.02994391436205465 0 +0.09225923695538597 -0.08865315842768008 0 +0.06866998855917444 0.02276819321505673 0 +0.1366012833891398 0.09544176691465661 0 +0.02341228942945175 0.09539204348700732 0 +0.0581021642072758 -0.003268029244693961 0 +0.1426979008084456 -0.00238925049555215 0 +0.06416370022864257 -0.08052144820838136 0 +0.04366642399978836 -0.07020155226176208 0 +0.1209153955975639 0.004822134913080656 0 +0.1194831768589359 -0.08556169855167466 0 +0.1130562017411302 0.05372035919457863 0 +0.09901980327603235 0.08133211082777428 0 +0.01166470553853274 0.01721632326767216 0 +0.07157260302776872 -0.06069531322308112 0 +0.09306040784281447 0.09622547250536637 0 +0.05927855714512786 -0.0123119366289964 0 +0.08422371789552119 0.01728381984671295 0 +0.1175170448425411 -0.07435734012662436 0 +0.09805453398169538 -0.04298480089341365 0 +0.06109956185868277 -0.07228918863924866 0 +0.08863552204461486 -0.03116266686361915 0 +0.02887435088270513 0.08285678653356793 0 +0.02441352017642042 -0.05031051314462094 0 +0.1394945055418919 0.07877455507542937 0 +0.03902087440879193 0.0500659085202502 0 +0.07144484882460873 -0.03146569062315892 0 +0.06369143709043421 -0.03546369210869668 0 +0.1068360701973981 0.006418816867651621 0 +0.03138923091565216 0.01542618005368015 0 +0.1239867242226522 0.02728042392184624 0 +0.1099042747803947 0.04413562758227291 0 +0.01124632909954103 0.06659863416819548 0 +0.05127372436675396 0.07564911179296052 0 +0.1122341370178673 0.0001533179209799449 0 +0.0195772641508791 -0.02970789892914193 0 +0.04621247370648207 0.01465408539854056 0 +0.03012742449434309 -0.005213691266772467 0 +0.02464753745533773 0.03067770557730225 0 +0.0950819316201251 -0.003128313538745676 0 +0.09533271449929515 -0.0813632604915239 0 +0.08151607764508691 -0.0108724007820156 0 +0.06972582437240386 0.02899781869724801 0 +0.06515826428072882 -0.01181194729970697 0 +0.1231094212134604 -0.07044340012176196 0 +0.06613030584203852 -0.0540214170814386 0 +0.1239241325643014 -0.0875763004108973 0 +0.147210275266716 0.06554193047780327 0 +0.1477429180237626 0.0212625901383291 0 +0.06971651669116782 0.09469665615044207 0 +0.1104127604675311 -0.07186145060265026 0 +0.131041499752889 0.0829760988449269 0 +0.1390123950521258 -0.0854068890404753 0 +0.05797140814297981 0.02773654224394908 0 +0.04528544241410019 -0.04966215548260783 0 +0.04220040791067042 -0.03439100265857827 0 +0.0634424626668231 0.05942421960257117 0 +0.04571283762200205 0.08223347342808218 0 +0.02412222691348514 0.02553546551040745 0 +0.004653984066143726 -0.01327705021810426 0 +0.08846391828653127 -0.01506053925666721 0 +0.1424601632879519 0.04250476253791525 0 +0.1038378152338636 -0.001261898742006681 0 +0.05969412010482272 -0.07744183394931012 0 +0.03085341540590911 -0.06234094030472011 0 +0.05221056275308617 0.07093173118688749 0 +0.0368418025342314 0.01727382180152683 0 +0.1426786902427759 0.006461092497531825 0 +0.1552046077309861 0.02468269692686111 0 +0.1555043527351169 -0.003302238596373509 0 +0.01300253018843914 -0.008856060639623957 0 +0.1494322811428259 0.0955540462294481 0 +0.0105935085163425 0.09561305810195571 0 +0.1088873452811128 0.07570044887996377 0 +0.1316463557464584 0.05896263663313724 0 +0.05681319870187375 -0.03542161117867909 0 +0.0203192981760357 0.07769253027205626 0 +0.09518397084209468 0.03365088648022406 0 +0.005595718463276556 -0.0307299926523413 0 +0.0510248064898562 0.03533840618707354 0 +0.01070726734840081 0.03398807400051821 0 +0.05761948220980817 -0.09603576715833896 0 +0.03082733217192416 0.04570260300547926 0 +0.05761656250198782 0.04099594181797693 0 +0.09106501725901432 0.06539618718066881 0 +0.127740570363829 0.006891686758114842 0 +0.03004112263675887 -0.09522979782232857 0 +0.06987506149556666 -0.04532941830066949 0 +0.08769226894724613 -0.07979570213495317 0 +0.09023166552806741 -0.07143178095932277 0 +0.09650758079223624 -0.01836981627781371 0 +0.04423068345247658 -0.01390147408118522 0 +0.04573061270480536 -0.009400516401408295 0 +0.1219285871905858 -0.02369083965411573 0 +0.01104032798270376 0.0484008215249186 0 +0.1393383645437548 0.03442881639089634 0 +0.08209025742657773 -0.06836166807051487 0 +0.09736456828115395 -0.09545621213879299 0 +0.1213385631699484 -0.01518944101970639 0 +0.01978763988488247 0.06192276516585038 0 +0.0778277226249138 -0.09526704082457561 0 +0.1355255889406592 0.04236928697869442 0 +0.02559820255979406 -0.0559548975406072 0 +0.01650684030270625 0.003769797103839275 0 +0.1402301352087587 0.02896802276816732 0 +0.1430013191837763 -0.02618982953975236 0 +0.1075203388060099 -0.08359312613423051 0 +0.1235352391779128 0.06938754338627003 0 +0.01592145704192706 0.05397822510247959 0 +0.09585424988099658 0.0886572505387342 0 +0.03876024462771291 0.09545635137868536 0 +0.1211742181765407 0.09536186166700836 0 +0.06897862457863843 -0.07362177071833578 0 +0.1141618634222043 -0.02642801774819725 0 +0.1170996044312667 -0.03064707351215274 0 +0.02230313413555642 -0.03990743276855532 0 +0.005156940017009962 0.07165340242347518 0 +0.09047099165992825 0.08667545549935626 0 +0.036468735617364 0.0694166851656222 0 +0.004454451297267696 -0.07035426440885902 0 +0.03545717675555256 -0.03915393619829527 0 +0.03595714655437407 -0.02904575848010264 0 +0.1083542449308253 0.07093971384300875 0 +0.01060206984186853 -0.03223344482281631 0 +0.08532421194099425 0.02640441359344098 0 +0.1261825571934292 -0.01492298801807031 0 +0.1565100422162237 0.06291290324100367 0 +0.1552203472869988 -0.03614362721173639 0 +0.06978999790421266 -0.04015609578414472 0 +0.1033124337291045 0.0649479430234043 0 +0.1107905080010619 0.08464592120051118 0 +0.04827438347208877 0.06747828733147755 0 +0.01030634156428579 -0.01530656363672347 0 +0.05680472826050915 0.001980125700326713 0 +0.04478905812798498 -0.07511843804205605 0 +0.123534829191601 0.05438438644836491 0 +0.02366089224009897 -0.001824895314666162 0 +0.1445079819382152 -0.05450431575014214 0 +0.01124550937528254 0.07899449016740374 0 +0.09778430493461028 0.05863052950519369 0 +0.06426902985147956 0.01463981042593583 0 +0.07849333217317717 -0.05312522282461088 0 +0.09561665181454117 -0.03512287948215538 0 +0.08041919651290619 0.04171109276342813 0 +0.07802417284472611 0.02432371666562177 0 +0.1561508987141898 0.03688268296411498 0 +0.05722140336225499 0.06524809794403234 0 +0.06915705064301989 0.08661166174599282 0 +0.03945035715764896 -0.002500762231547819 0 +0.01099718513976494 0.02505749063441636 0 +0.004442806546549207 0.06383726988215434 0 +0.1188813264614529 -0.00988697409780576 0 +0.1279335857375937 0.09066234659271746 0 +0.03240114354134797 0.09041246524512572 0 +0.04282942243686307 0.03861793922920001 0 +0.1488711720903535 -0.008565348877212785 0 +0.09111849542225445 0.0788018342091151 0 +0.04220902256950519 -0.09623129400150725 0 +0.09874601969147953 0.02200971538665224 0 +0.003915538165567336 -0.05807375637118132 0 +0.0271816458003089 0.06007005056837255 0 +0.0171507675368079 0.03157557078681456 0 +0.1198552250222638 0.06703442002110238 0 +0.01839907929178241 -0.09557445882442911 0 +0.04824173385232966 -0.02279406502357795 0 +0.1253873425382636 -0.07762678784355154 0 +0.03771457696507702 -0.06898473295131598 0 +0.1156705423868738 0.02635759668808631 0 +0.04739044884806032 -0.002165001291795038 0 +0.1312557376182848 -0.06561860344862079 0 +0.1272661996183608 0.03488860772017894 0 +0.1496026134202574 -0.03661786435698014 0 +0.004091604530037209 -0.08161554239683666 0 +0.1489261120478636 0.01196607719183438 0 +0.1300451808459407 -0.02583343275340217 0 +0.1158071997497172 -0.002072719712276851 0 +0.07825726871663412 -0.04378743764929868 0 +0.1083018039098214 -0.04499160453651947 0 +0.1562915393756575 0.08164656665130576 0 +0.06231285102482827 0.08946766722527869 0 +0.1189894808991014 0.04734898201296617 0 +0.07085992503954158 0.03806287958023512 0 +0.04795669088565778 -0.0828179332983229 0 +0.1012981993812751 0.07772057762374282 0 +0.1366752498306711 0.009092786993809219 0 +0.1067871714116566 0.06113507772300045 0 +0.1273965159820906 0.04456315463383483 0 +0.1207563906258801 0.08682431492754715 0 +0.1040782602631234 0.01502620785899463 0 +0.0389686850691618 0.08672383006117804 0 +0.08925307109698351 0.04711995026019798 0 +0.111776506956788 0.01323860406285553 0 +0.04018544253343024 0.06710744958579951 0 +0.1489961436192847 0.07665701633089564 0 +0.1264713992336043 -0.03385137012812368 0 +0.01007468822213228 -0.02263971346303347 0 +0.1484559441477467 -0.06797982602878887 0 +0.1199692117914496 -0.07919637374858812 0 +0.09720486652869968 0.01127576708399752 0 +0.07222744028274344 0.07122540091204495 0 +0.1411934136549073 -0.0394807865711699 0 +0.02505176772456849 0.0901795076036478 0 +0.1330975726684311 0.01375296216652698 0 +0.05112869074861203 -0.07969532531724975 0 +0.1173287291214282 0.01929884257229377 0 +0.02948927769990994 -0.01834089995567213 0 +0.02146227663440912 0.04528217627402245 0 +0.1472160071443596 0.08027979683450071 0 +0.1119973338620122 -0.06719521486231424 0 +0.07693238880300948 0.004385453023197256 0 +0.1252980525234192 0.0225539000612628 0 +0.003724841061488993 0.08250000000000003 0 +0.01083142513119376 -0.05490759837874189 0 +0.120465254548643 -0.03879410565544317 0 +0.05906015685510965 0.009257799681626329 0 +0.06089392963217141 0.01868342453492415 0 +0.07354105115976386 -0.0517123515564223 0 +0.07457749868901226 0.07869599225892651 0 +0.1376977988337361 0.05127115552038171 0 +0.0454971535341176 -0.08968417140786401 0 +0.09872335073861378 0.004402415544228684 0 +0.1486874117791118 -0.08404777720861571 0 +0.06268787308258537 -0.05616585740376168 0 +0.09186058668087427 -0.05341674249567809 0 +0.02760953173148314 -0.01051323315250692 0 +0.1550055063921306 -0.01742129872767873 0 +0.1015363827761473 0.05088635620385112 0 +0.02859026367984734 0.01880451822601103 0 +0.09324156419875998 -0.04567493621242449 0 +0.1408048222234024 -0.06225936286947996 0 +0.1440558235736671 0.05691846929013607 0 +0.06565394826132874 0.03922719319325491 0 +0.08350344837464095 0.06358012422579845 0 +0.1371734722010288 -0.02475261440515203 0 +0.1432504579207262 0.02134552327304792 0 +0.05621387020215944 0.04918524668238086 0 +0.1455127207611136 -0.04612660228889505 0 +0.1015628359256093 -0.047551868968333 0 +0.08321470266535599 -0.06043352393588659 0 +0.1299758660706559 0.05348719388833369 0 +0.1332049715613079 0.05027190751362885 0 +0.06918036283026924 0.06585697305367123 0 +0.10256768119222 -0.09542477902170877 0 +0.05927041936191993 0.07681950606916131 0 +0.1485964657806127 0.002786333252210783 0 +0.1079116089052661 -0.007295675131924881 0 +0.1555964176085905 0.08993712921710889 0 +0.06531814834815007 0.001205312133400822 0 +0.06016431406619956 0.0829363715208621 0 +0.07691160553220212 0.01935056948261751 0 +0.1142881976905314 0.08174701752138837 0 +0.1040905443407267 0.06968419627973677 0 +0.01471524836609931 -0.04215861405547362 0 +0.1119404196349972 0.06769197072935323 0 +0.08163863590024642 -0.001795003152677872 0 +0.1120610271333744 -0.05458504739972043 0 +0.07625566763301656 -0.01756259076706581 0 +0.06738470521420684 0.08163007226996226 0 +0.05101250283329251 0.005318422686321789 0 +0.004106799533510109 -0.04402601352634408 0 +0.1432605996048273 0.07172046214231718 0 +0.1179949589354275 0.007702557168367622 0 +0.02433903917511339 -0.08892846565264341 0 +0.04522042908998326 -0.05751391278026521 0 +0.090835394131286 -0.02341013150091734 0 +0.1291727738184719 -0.001894611319886253 0 +0.09658444677518499 0.05096219504107755 0 +0.05733178121855508 -0.05261552687565427 0 +0.09998223533345288 0.0175217527618853 0 +0.1355254925951346 0.03654505924658819 0 +0.1349755993148221 0.0903198181826885 0 +0.1190977616794455 0.01550718948842669 0 +0.1493815453206565 0.03932695429460333 0 +0.009915926835884884 -0.09605668127870698 0 +0.0657571668591266 -0.03160030480140057 0 +0.1553941703029362 -0.06451168262935701 0 +0.08219474097650287 0.05020917014667939 0 +0.0321836811187742 -0.08883131175147418 0 +0.04057539956140195 0.04545602884953139 0 +0.155906459560076 0.0164260731665823 0 +0.05731358339406049 0.09604502698230691 0 +0.06511185743353878 0.09567068065234423 0 +0.1027263594748596 -0.07738251822134246 0 +0.01020261312180528 -0.08453075252001162 0 +0.1151529449897908 -0.03911652866891491 0 +0.0522137743010442 -0.05422646635316573 0 +0.03119994311617509 -0.07978590197257396 0 +0.1188536497341381 0.04216581495838596 0 +0.15601254022324 0.003361726127975086 0 +0.1560152911932143 0.0116325572139404 0 +0.09753656318274669 -0.07713671376931142 0 +0.03686430086028884 -0.02019663245281426 0 +0.004030621700134746 -0.09004588746755728 0 +0.05622049844266078 0.06964394041830148 0 +0.09556000792078617 0.06693119323914185 0 +0.1348702976433431 -0.006134728709277748 0 +0.1321290956998343 -0.05353988642486594 0 +0.1112290754149547 -0.01994514926458148 0 +0.09913525281447866 0.06393124170604932 0 +0.03772158038633773 -0.06257362733722249 0 +0.05193241058582366 0.05330569324456984 0 +0.1268888822662394 0.06106562019090774 0 +0.03034823021724046 0.07538142407603501 0 +0.05249999999999999 0.09652896334143364 0 +0.08128118305304016 0.08508725956650465 0 +0.09960207093843301 -0.02269880220413116 0 +0.04395843978014572 -3.196693108593053e-05 0 +0.155733427586455 -0.03016394359319256 0 +0.09662256999414709 -0.0905641097948597 0 +0.1014449411378974 0.09598705443921399 0 +0.03470272264032611 0.06071113685298861 0 +0.05321006813246712 -0.07276281247685698 0 +0.08429906865534804 -0.02516156348144519 0 +0.01066209016327024 0.00808628967863405 0 +0.01181629327409191 -0.06849678653671168 0 +0.02003301412497688 -0.004051168970989706 0 +0.155856131802938 -0.02230325566954639 0 +0.09009309073549288 -0.06619279184875752 0 +0.1444036623701216 -0.0147569781993654 0 +0.1376403529328949 -0.05904409951060985 0 +0.05001574354183912 -0.0498427568641415 0 +0.0700980461953877 -0.055678600316983 0 +0.1458328779304419 0.05254161620495145 0 +0.05938602635133806 0.0562048837691451 0 +0.0721226540887632 -0.08300971875335658 0 +0.099748613047846 -0.004328168075674254 0 +0.01379452956809054 -0.05885911998605723 0 +0.08820718555351403 0.09584841572924502 0 +0.0684252744922331 0.01560978496717595 0 +0.05118833099717305 -0.02608389303442525 0 +0.1424774682209113 0.01390067683294599 0 +0.15022375768634 -0.02811913207658239 0 +0.07361484333949823 0.001610403917430228 0 +0.01446189682357184 0.0458447334570745 0 +0.06022940880390854 0.05189687637898326 0 +0.1499592891750185 0.06895164753390531 0 +0.1187661343488262 -0.01918021534499478 0 +0.1405779967662489 0.08630028504313064 0 +0.1237591930065483 -0.007611828147958703 0 +0.1563501003364572 -0.04791881920899347 0 +0.003376499738651668 -0.002499999999999992 0 +0.1216046715462596 -0.09610572298150338 0 +0.08291196867748396 0.09624789666770441 0 +0.07110290438688593 0.01049308885369284 0 +0.09186544470266715 -0.02722086373488069 0 +0.1509448789873721 -0.003674512370062289 0 +0.05397977759924906 -0.06021915592553601 0 +0.09134540191899025 0.006017449132649896 0 +0.08015773850220922 -0.0344802924888799 0 +0.06203622909926715 -0.04261859579647374 0 +0.06746284758535015 -0.09640289731354293 0 +0.003872452441980945 0.05925223395943147 0 +0.01844465468237753 0.03851259689996535 0 +0.00378297837131104 0.01714112927327646 0 +0.07049623638028335 -0.02236046599176528 0 +0.1027018047594862 0.002645003845896188 0 +0.1565196619125794 -0.08241802379937141 0 +0.06520216201287203 0.05091064958819663 0 +0.08402894999538836 -0.07687103031900978 0 +0.03009648116128783 0.003950944207327126 0 +0.07834203392030251 -0.08628043776265627 0 +0.01935871574492615 0.08627925277752989 0 +0.1133300309100311 0.09622626634318995 0 +0.09666639898411808 -0.06439599961521231 0 +0.01907483433599647 0.01837180544624608 0 +0.03158222283829712 -0.01367342950657596 0 +0.06449493339731696 0.06775620109233596 0 +0.08860270579369289 0.07084018176051345 0 +0.02320610241168685 0.05862745835318628 0 +0.03977311981382162 -0.03766508979151964 0 +0.05904931425040685 -0.06443043899624724 0 +0.03198565636728368 -0.05198172571891719 0 +0.1019694938455262 0.05609170160110018 0 +0.112445600667456 -0.04560040676335563 0 +0.1262335778702559 -0.02278269584043715 0 +0.08615928034780693 0.07858799045057875 0 +0.1272476445072808 -0.04181048495506658 0 +0.0324455853553275 0.06804361816441269 0 +0.02531342801354118 -0.06661377643448363 0 +0.1285986153889855 -0.0909092264708001 0 +0.05061585541765651 -0.06382689783634546 0 +0.1391864577316182 0.04408828163721736 0 +0.05913133228674931 -0.01627211477503082 0 +0.1414624332505075 -0.01098570391057362 0 +0.1413315899056473 0.09596651905286423 0 +0.01841487247977552 0.09619997779313325 0 +0.1498145690994889 0.01668255323989611 0 +0.06130050819629203 0.06422560239295916 0 +0.1080492623661612 -0.002357599155979102 0 +0.004054948447262154 0.05138535594153541 0 +0.02936410304689813 -0.05866687908073299 0 +0.03364840380721839 0.04956191054893104 0 +0.03206528884890774 0.05383786877897762 0 +0.003759270966377248 0.02834735791083399 0 +0.1287236864900136 -0.09609803526988549 0 +0.08194904049046783 0.04555821475977521 0 +0.1159613416812929 -0.08991027902394617 0 +0.0191279546056206 -0.04368407116672771 0 +0.07012764141120577 -0.01325778082726191 0 +0.08700976420132764 0.05083891857976083 0 +0.1084437762524267 0.05343228813906026 0 +0.0841393195606063 0.00802766375593084 0 +0.02261433572406572 -0.09653816497717566 0 +0.07306504952302433 0.04217234516850012 0 +0.103991749065504 -0.01520715853646272 0 +0.09836368596153473 -0.06893077100028658 0 +0.08888639451262914 0.0019791011131612 0 +0.04395301913934392 0.07357120084749993 0 +0.03317227955617688 -0.03261941407553064 0 +0.0214418468350622 0.08224017576637163 0 +0.05459939046609892 -0.04639801880824488 0 +0.1004195953314588 0.09095395577913809 0 +0.1031720254762878 -0.08164261372717968 0 +0.01145171339640928 0.06263482044039231 0 +0.07337800868102501 -0.06787037974731447 0 +0.02033121790699579 -0.04870769451595724 0 +0.1473765618691478 0.0346065869512024 0 +0.03130564698097265 -2.628859382373398e-05 0 +0.0254418423802521 -0.01789806289726303 0 +0.003630293151261992 0.03769819011162217 0 +0.1392321704670702 -0.04680884060777636 0 +0.06552582323532634 -0.07020851838185294 0 +0.1559873808734988 -0.0686731489394118 0 +0.02235353330301468 0.05377610120165024 0 +0.08362242421464523 -0.01506447593728141 0 +0.08526380272976794 -0.06486713542382289 0 +0.009863293459525892 0.05730519862334253 0 +0.1035357831420557 -0.09073404155519252 0 +0.04933379691419507 -0.030624405992309 0 +0.01720497334803546 0.01141666807541078 0 +0.1386538870682741 0.08274950101392191 0 +0.08022832456906363 -0.01893785788692919 0 +0.1320443404990353 0.07825207553590732 0 +0.1225140644500862 0.03633471004340478 0 +0.02854488424657197 -0.02663927114332854 0 +0.0282301363379631 -0.03156907358336282 0 +0.004319435087796143 -0.09569674417769441 0 +0.09781467355503999 -0.0276143641324377 0 +0.02734777018933396 -0.04481931513035325 0 +0.06251487258728715 -0.01975283418706279 0 +0.06641933169306513 -0.01661909818079158 0 +0.02555737278275115 0.05103690379554705 0 +0.05057026860554871 -0.09599804251216465 0 +0.004008534079911615 0.09051340677789478 0 +0.02724614113018368 -0.07343821257002259 0 +0.05799343702852955 -0.08517379494447827 0 +0.1344487144948738 0.02157245816733261 0 +0.03623531703610863 0.001055899569306662 0 +0.09098638911246627 -0.002033271689026768 0 +0.004031161972593057 -0.04991732783320402 0 +0.1441157963914414 -0.007114488826734572 0 +0.07852630030924289 -0.004123388913030593 0 +0.1494222004220162 -0.05181924719337089 0 +0.003514971944606342 -0.07798866634244701 0 +0.05167711235021093 -0.0098118368525604 0 +0.1510015597039436 -0.07115977143531457 0 +0.1219517442848027 -0.02820154624488075 0 +0.07368189427673952 -0.04662306513617365 0 +0.01831135393937709 -0.0833141317025235 0 +0.06568863675081038 0.03033569567048909 0 +0.06506359728192296 -0.03920536147857345 0 +0.08813606101530484 0.009692854708286796 0 +0.09549147089737986 0.07203605262592885 0 +0.07386655783794546 -0.009976646740937128 0 +0.1097311933408574 -0.06389627434629372 0 +0.1131188365446696 0.07707123119587805 0 +0.07628161136412205 0.0639223476281275 0 +0.05568576885157385 -0.02450149480025831 0 +0.0547234819523295 0.05723647653682951 0 +0.1352611143747557 -0.06856618625791379 0 +0.1355045652488685 -0.0732186096354264 0 +0.0418209859430241 0.01440813106518514 0 +0.08559046593306439 -0.08437579417396476 0 +0.003493398739479721 0.02121040888583643 0 +0.1320986003768633 0.03253445691679431 0 +0.1133344546558982 -0.03436983738953495 0 +0.1272305361461342 0.06784957427375889 0 +0.1420857768709453 -0.01856698182671734 0 +0.02628158872712909 0.03655764649258194 0 +0.1125 -0.09690873554251113 0 +0.05777026446391405 0.09157187261994411 0 +0.01907996863321529 -0.01306305841225451 0 +0.09504411880749784 0.05473525133090734 0 +0.08576043981602106 -0.04675864145093239 0 +0.003727398613613519 0.0463611900046797 0 +0.1560710920317464 0.07336286766872835 0 +0.01504564527006847 -0.02273377737617746 0 +0.1006149689355875 -0.008404380821848932 0 +0.05320690586798036 0.08962408146991835 0 +0.09238130979557299 -0.09651573439881242 0 +0.1392451847593509 -0.05510318783764624 0 +0.137688483994673 -0.02034679971404217 0 +0.08799361802107487 0.09012936768892239 0 +0.1157682432936332 -0.006318019935626949 0 +0.1521820424585311 0.00507189926702869 0 +0.1488723185748456 -0.02127088230459877 0 +0.156162338317489 -0.09616869092702007 0 +0.08095110865134075 -0.04805497653116666 0 +0.01838163924831238 0.007211161764995865 0 +0.1296974704352682 0.07491593805620773 0 +0.05613350088914763 -0.08082939678796477 0 +0.1561074942970906 0.04442466265797719 0 +0.1567957729191983 0.07771714949293752 0 +0.06986341585554083 0.01921409272988544 0 +0.150363958497187 -0.07923448091286364 0 +0.1202147330972964 -0.05395514006151111 0 +0.1340558387922924 -0.0406616720522897 0 +0.1330318879788301 -0.09611527217423572 0 +0.085016827001832 -0.02936104418892643 0 +0.1109838064031235 0.003861329433561753 0 +0.1022988253904709 -0.0298245476064298 0 +0.1228035800438483 0.08226606102076224 0 +0.009687731976964533 -0.006412220527574125 0 +0.1162950612269327 0.07370933052419824 0 +0.0629603654827529 0.0108636622412191 0 +0.1229622285320165 -0.0626766736590697 0 +0.1409100198633055 0.00190825292999872 0 +0.1414227821582845 -0.09619118146677152 0 +0.06270636886110545 -0.002727473593150146 0 +0.06274242391751092 -0.08480756448106844 0 +0.05327799350149595 -0.005380253236927878 0 +0.1359209767308777 0.01724051974120779 0 +0.07485023426661634 -0.08611464156687604 0 +0.1178760074667626 0.03507932933683456 0 +0.0407096037009942 -0.02061358674736691 0 +0.009048027919436319 0.08555988398244957 0 +0.08345108296455686 0.07609283744676348 0 +0.1175 0.09701447081050801 0 +0.04373551410984341 -0.08154938832773914 0 +0.07783307445062394 -0.06602512557107118 0 +0.08323916877722851 -0.03739718674468929 0 +0.01031132063078 -0.0008537807246103741 0 +0.1504446395158507 -0.06440938620319683 0 +0.07722765145981883 -0.07370890545724144 0 +0.003666461928369215 -0.02683338993836421 0 +0.05283121507201855 0.001972449020760715 0 +0.06315993513294586 -0.06309145009187629 0 +0.01556782521395852 -0.0001190613782354653 0 +0.04052159412169528 0.06208285537091746 0 +0.06190295315559218 0.02683074980407103 0 +0.009670063227635606 -0.07521655405257761 0 +0.04936981224424378 0.08571178745549057 0 +0.1447722769986129 -0.02204743197562192 0 +0.07399988662125298 -0.07927014125799327 0 +0.1268927264082645 -0.02992816542943358 0 +0.003304831016289936 0.06761272079372142 0 +0.09359208421764563 -0.04967603309828517 0 +0.02875995414946679 0.01089825518955656 0 +0.03509521993426213 0.05680329097846778 0 +0.08594323783722516 0.02139920441025223 0 +0.02447436564777652 -0.02464215535278032 0 +0.09201409444235513 0.01616442707312246 0 +0.07332121461679326 0.09646143427147902 0 +0.05726240527832269 -0.04236796153803522 0 +0.0678434734402769 0.06112124139020006 0 +0.1324529161688882 0.03955293936269388 0 +0.1194576212185918 0.06262881771644675 0 +0.03759050328938872 -0.05689154464302245 0 +0.08650860879412479 -0.00659953668869786 0 +0.04762652268028027 0.006318800216505042 0 +0.1056365234659166 0.05028832898247483 0 +0.1415034839580352 -0.09085948674647387 0 +0.1076690023971175 -0.04114364526068458 0 +0.1564551275600145 0.03266098892071573 0 +0.05017083275159513 -0.09154999807125323 0 +0.1158623025714472 -0.07820465454592807 0 +0.1068374379895127 0.09010400417244566 0 +0.03717531210134067 0.08236169562973908 0 +0.008374933168926244 -0.08907741584351406 0 +0.1392566686337819 0.0695549599079999 0 +0.07135181802718295 0.09050750853899327 0 +0.07058334043742112 0.07910668096294443 0 +0.04467561375780173 -0.03120846011815506 0 +0.03499228211173151 0.01392724988917978 0 +0.1092588754646806 -0.07617108756860452 0 +0.1275694819284176 -0.05408613484972517 0 +0.07328023826850899 0.04967190870260801 0 +0.008394368057777397 -0.05020441032188295 0 +0.02846058103113125 0.07869547618490573 0 +0.1404572047317023 0.009556816743318472 0 +0.1438636042454397 -0.08278763723790135 0 +0.1523596432984835 0.009489895674581535 0 +0.07258748549860122 -0.0717632074995426 0 +0.1059868305487582 0.0964466717476295 0 +0.009589916147714633 -0.03692751198246464 0 +0.1559557368231254 -0.09199236969557928 0 +0.09005210226941779 -0.05789659645234355 0 +0.02776074274014841 0.06718654313049537 0 +0.1295229334513757 0.003389472448081222 0 +0.1324981411625069 0.06717635594515171 0 +0.1525506222612392 -0.09704049792337718 0 +0.1571414805677452 -0.05250000000000002 0 +0.1072374948643382 0.08262105509726711 0 +0.1296979375858177 0.02078271761124591 0 +0.1167772209647951 -0.0665681272920641 0 +0.1424539870837813 -0.04762907200901087 0 +0.04715063414009255 0.07731595328756005 0 +0.02366080200680581 -0.03210148946024823 0 +0.02467693448540732 0.01048930700847955 0 +0.1047126709456144 -0.009766594583590339 0 +0.07556012136330871 0.07478422572932303 0 +0.1211087853488985 -0.04572883939507305 0 +0.1036072389564812 0.01016863038011612 0 +0.1216137793691966 0.04009613470973747 0 +0.007330174008967929 0.01552057428738312 0 +0.003394665255159037 -0.06668076098520266 0 +0.02611835176188315 -0.08552545316834831 0 +0.003742478473648523 -0.03556459207667362 0 +0.03361179089395904 -0.09648050807427894 0 +0.05738464220957738 -0.07396091505638064 0 +0.00760928346311652 0.04032944382911968 0 +0.03977994292997038 0.0363445686099627 0 +0.157166353385706 -0.007500000000000047 0 +0.09475932884903364 0.03003729805532558 0 +0.04071001361375598 -0.08809144130747999 0 +0.1512145939955294 0.04482817651214938 0 +0.1192434800341731 -0.07059868305172115 0 +0.08152452310249779 0.03263309967016671 0 +0.05950373296952419 -0.0492423040172 0 +0.1324892663564519 0.0462871723703053 0 +0.06839418612755754 -0.02861585125972573 0 +0.05924513227639952 0.03449972506313147 0 +0.08734517579035896 -0.03607733204845251 0 +0.002956387347326928 0.007388413978558352 0 +0.1504896415907711 -0.04190540560535668 0 +0.1110626018104012 -0.09014044014023506 0 +0.1193575469162181 0.09087625241967441 0 +0.08759479030839405 -0.02252241657551233 0 +0.1335685660181212 -0.05816126046418825 0 +0.06777130574444887 -0.02515702349820178 0 +0.08063075528827218 -0.09042068658317623 0 +0.09961502764035846 -0.0838991544003955 0 +0.07108583045097666 0.02581622167618115 0 +0.1507438199388507 -0.01814723014176537 0 +0.03492176358426505 0.009241499610293089 0 +0.1344072682263968 0.00417797667861689 0 +0.02897106599461235 -0.06553118524152519 0 +0.1566297130871332 0.06641141508174624 0 +0.05894505214309327 0.005094441224409102 0 +0.1450554348256032 -0.05936905026597712 0 +0.1091514966155839 -0.03210168336747923 0 +0.07977760756477924 -0.08285513482000392 0 +0.1321902435481335 -0.009526888743472432 0 +0.02060046361351849 -0.07693461128700907 0 +0.059310016149652 0.07263633113631038 0 +0.01132151686980468 -0.09185766615782046 0 +0.009881297670689777 0.07003463206103114 0 +0.1563003932342708 -0.04054356367258888 0 +0.03327210799668322 -0.02631550922945144 0 +0.1243998715242435 -0.04794424249873777 0 +0.1283928945126847 -0.04600609419596259 0 +0.01356562431263595 0.01267749926091583 0 +0.01735017430194884 -0.07925295265371131 0 +0.1179789852497613 -0.02329855666969625 0 +0.03076963490859618 -0.07189279341521573 0 +0.01692358145690703 -0.03573296948268112 0 +0.02802183754276807 -0.05211941590533115 0 +0.009907975948316088 0.02160162819285355 0 +0.04063503480796276 -0.006976553955548838 0 +0.1086816018985591 0.03001120841231893 0 +0.09263389795951804 -0.01548092781835704 0 +0.03889695965415207 0.05517692756883993 0 +0.1564221182386059 0.0971154482667381 0 +0.003577881761394195 0.09711544826673814 0 +0.1340911144784435 0.07129035689128471 0 +0.04261555191949242 0.09718641865895716 0 +0.09973448668064716 -0.01509165633115117 0 +0.1264917002097434 0.05256612110890344 0 +0.03055360958558182 0.03800752724998058 0 +0.06800247755535249 -0.08859877393407707 0 +0.1290990033038686 0.03963453668787933 0 +0.0179436381179689 -0.05805930206949154 0 +0.04063701571955439 0.09091121373623018 0 +0.0234966428248368 -0.07971896289793487 0 +0.02734677219204285 -0.07763778594642988 0 +0.03010685110072568 -0.09163090114081059 0 +0.08849493342272169 0.02910547805959698 0 +0.1489918275407299 0.06180216039306634 0 +0.07123350278798279 -0.06516089709302031 0 +0.07623637596787075 -0.03984311588289279 0 +0.03776931422106299 -0.04612691037530076 0 +0.03786142907952303 -0.09125685924622473 0 +0.1126358768158036 0.09258756963157141 0 +0.1569582172746826 0.02805082496938883 0 +0.08181270412528269 0.09211846873781886 0 +0.09547392283005361 -0.03874283027674329 0 +0.09994399241437768 -0.08819530094593066 0 +0.09042923023286224 -0.09263752905759376 0 +0.157031625270441 0.0563542707607712 0 +0.0759416007258293 0.09046519371226482 0 +0.06932052494274894 0.07359523026023719 0 +0.0188853077277572 0.05191550062756058 0 +0.1201237773934607 0.01149862173642371 0 +0.09799450875447277 -0.01124218399574367 0 +0.008361885346550479 0.06439871686309386 0 +0.132951173155535 -0.002680154600451668 0 +0.08524783028397254 -0.07209942515666458 0 +0.07720429049098075 0.0567912939144477 0 +0.08623984360137235 -0.05804888999075866 0 +0.09927153685911683 0.008416598547013853 0 +0.09711151016016276 0.01906747828492831 0 +0.002928794934891095 -0.01759416428391888 0 +0.008320058899461018 -0.06282027764746886 0 +0.134890606543907 -0.09261936274423449 0 +0.02159452548837437 -0.007322951674720018 0 +0.1058660825367763 0.0787717608373948 0 +0.1071332929828274 0.02700140903562769 0 +0.1100979130515179 -0.0278556440560507 0 +0.05097999246807229 -0.002287175266340531 0 +0.01682817417520766 0.07368405511992708 0 +0.1171836971208938 0.02295162837146274 0 +0.1398615487445548 -0.07563728784359522 0 +0.1148376184320399 -0.04344834457006757 0 +0.1469654506848682 -0.0006152267376949589 0 +0.1061010991055574 0.05711295917706249 0 +0.1011724098673871 -0.04079973474663805 0 +0.008456600688458847 -0.07095217012870242 0 +0.01715501615456184 -0.01645200239477561 0 +0.09316846173254632 -0.08431589687578799 0 +0.1525000000000001 0.09735331019692609 0 +0.007499999999999995 0.09735331019692618 0 +0.09021214022122975 -0.0388965849423302 0 +0.04135868700342937 0.0576157046829162 0 +0.03329648559045571 -0.006165074726451633 0 +0.03239722119797935 -0.06885347302132505 0 +0.008776798133169957 0.003802001888772832 0 +0.1380420037906444 0.05432924313609468 0 +0.05433614775551204 0.07808616387056448 0 +0.01505916766107342 -0.07150131738411222 0 +0.01339754222831433 0.03150293679059384 0 +0.1230870000671562 -0.05848318274656137 0 +0.0163281640787727 -0.0908354227460305 0 +0.136232886186424 -0.05269036415465365 0 +0.0975 0.09737457233386977 0 +0.1022547496789905 -0.03613417874017066 0 +0.08236505280363418 -0.04096318188901502 0 +0.05488489265225306 -0.03876838966677841 0 +0.1366559445777704 0.07657545600471959 0 +0.04538216466258795 -0.04222831370541716 0 +0.01424479517619095 0.08081245662830434 0 +0.07782172347717116 -0.01154388090167282 0 +0.02395941674758749 0.00211395152372085 0 +0.09955727555806997 -0.05077987069512491 0 +0.06405579146700316 -0.02438811685383182 0 +0.02752702544604026 -0.002467450766843934 0 +0.01435270648809832 0.04160417901692592 0 +0.03479443235728488 -0.08214564646501472 0 +0.1521641403687934 -0.09085500083660947 0 +0.1166220109078068 0.03941675916171538 0 +0.06188272751703548 -0.02833013464597579 0 +0.07098729736255921 0.003545759651576825 0 +0.07429346412596544 0.03480163942066027 0 +0.1272646076135013 -0.005668635109939153 0 +0.04942178253552988 -0.07607217539556092 0 +0.157082634510241 0.04789032823767356 0 +0.114658140220689 -0.01776465590008371 0 +0.06590727904406907 0.008568123617187416 0 +0.09158525236317683 0.06171071806396367 0 +0.1323761556445544 0.09713150261946486 0 +0.02762520378891568 0.09712401133093815 0 +0.0311209079808556 0.007584480999616552 0 +0.1462722887686296 0.06936187507378587 0 +0.0565082305155239 -0.03196779528387531 0 +0.1455111674863386 -0.09071172119061087 0 +0.1282590504691939 -0.06365492310274785 0 +0.1515154443588962 -0.02395297235971425 0 +0.1509366057039642 0.04987274269906194 0 +0.1455187652967891 0.02911003778883871 0 +0.007941989891486465 0.05256719263877024 0 +0.07624724745087635 0.007890115589399773 0 +0.01833109527551237 0.04758926330191777 0 +0.09942659543055372 -0.05533421170173296 0 +0.02059925080569936 0.03191488477264326 0 +0.03342898388300809 -0.05598375334412407 0 +0.1268787143337131 -0.05765024573542075 0 +0.118312005697295 -0.06299357933588592 0 +0.01600527333278629 0.02474513645806612 0 +0.02418192394889635 -0.0139920851143662 0 +0.1240323075542442 -0.05162923192710819 0 +0.07601335351513515 0.01501554749753906 0 +0.1029245441566122 0.03326746027978341 0 +0.1519518439064571 0.07208842191662615 0 +0.1459095120608301 0.005439655644025612 0 +0.1150326835732934 -0.0511470508262758 0 +0.05946150379805068 -0.05546144397189645 0 +0.007651339061319085 -0.04330627924045188 0 +0.123044032680813 -0.04136490202358388 0 +0.03006635649268874 -0.04030745242862797 0 +0.1103678780747232 0.02126874818127949 0 +0.01872950652183616 0.03466688024668536 0 +0.03744900977143951 -0.07419423648346547 0 +0.1334179536612543 -0.07968035435923415 0 +0.1368665376985238 -0.08092900306883827 0 +0.05137728112702615 0.09305965459610072 0 +0.1036896206223069 0.0892339181217677 0 +0.06598605866883375 -0.008222808815792498 0 +0.02701440779688904 -0.09707999873716246 0 +0.05849814384594687 0.04465590661628653 0 +0.1122609085173679 0.04647978389843123 0 +0.07711954862132531 -0.03665630051088858 0 +0.126165308545597 -0.08439152581397669 0 +0.05622390972825284 0.08377274152131665 0 +0.05314297099493243 0.08242832912516201 0 +0.05730521067151133 -0.09238934553953268 0 +0.1521328838805773 -0.01092891958256987 0 +0.01579131106042345 0.01906489250415856 0 +0.0916020314689495 -0.08137804785193489 0 +0.1459858401439851 0.01398425790518668 0 +-0.01233223944094649 0.1497014872334691 0 +-0.08750000000000005 0.15 0 +0.09231641389158188 0.1505198308284492 0 +0.03671407119506409 0.1503396215326949 0 +-0.04992869492268358 0.1392247972278123 0 +-0.1224807512214611 0.1626261782736455 0 +0.1241809547970241 0.1344043625042507 0 +0.06512829268166331 0.1323026612433692 0 +0.06502976190476198 0.1674538690476191 0 +0.1184834954044148 0.1665904651489282 0 +-0.1138804959602991 0.1319467727781645 0 +-0.06185945342581918 0.1679730156556568 0 +0.01231595986567652 0.131151414757022 0 +0.01252976190476192 0.168796130952381 0 +-0.03274304722806786 0.171439994921175 0 +-0.02609991141404532 0.126600915221334 0 +-0.07400284263001869 0.1266687134509105 0 +-0.09925148031998796 0.1739019648049076 0 +0.1001897613162835 0.1253128594926978 0 +0.04030648835371804 0.1248285389123215 0 +0.04102478709059428 0.1748904213897392 0 +0.0889924518111527 0.1746846917699591 0 +-0.1361846215365114 0.1427782403568212 0 +-0.01005885008825883 0.1762669668812468 0 +0.1375482720217099 0.1536891596779795 0 +-0.1377268819336405 0.1784853531277796 0 +-0.09433762704191211 0.122460324935601 0 +0.1385873845027437 0.1779144604885473 0 +-0.1328485131710261 0.1215900604333346 0 +-0.005873975796486395 0.1210168676394401 0 +0.1393026396249492 0.120697360375051 0 +-0.07909647772744471 0.179476282865386 0 +-0.03315187105851704 0.1510563715511041 0 +0.08115551290417811 0.1215248641305348 0 +-0.06709690422470795 0.1490381781132358 0 +-0.04533414487776475 0.1185225970491471 0 +-0.1077490580941678 0.1510457824341306 0 +0.007397523156395767 0.1510598220192758 0 +0.1107847349933516 0.1503640246165636 0 +0.07302052578349781 0.1498933505800302 0 +-0.1169821733259969 0.181557769817715 0 +0.1069476842539166 0.1810833301383714 0 +-0.04835182552114185 0.1818731061227991 0 +-0.1409296667294411 0.1587132551643119 0 +0.1177918851589002 0.1183732763984709 0 +0.05538976968783863 0.1477182902434037 0 +0.02467421495157065 0.1186233893502357 0 +0.02518474817576275 0.1821523176729121 0 +0.05616867014201302 0.1175754404833228 0 +0.05689232281544207 0.1825568641102298 0 +-0.04904459125267192 0.1561575472336376 0 +0.1027114700229292 0.1644423709985611 0 +0.07251189837704704 0.1832954946352522 0 +0.1427110658844892 0.1375226199937767 0 +0.0282560056041632 0.1358375512565342 0 +0.02846487127465632 0.1639525933823402 0 +-0.06105906695035293 0.116510594641608 0 +-0.07739588928918258 0.1628485293731589 0 +0.004806110014387898 0.183664257430839 0 +0.08237237751487299 0.1375217017555665 0 +0.123004748632603 0.183771155144565 0 +-0.002076142706684022 0.1371383701798738 0 +-0.1096459027782941 0.1159990826199593 0 +-0.09801571560596924 0.1383493551427438 0 +-0.02329131950702494 0.1839695019796486 0 +-0.06380351887649489 0.1844349028899553 0 +0.008978909441075942 0.1157319899108912 0 +-0.002713815022330272 0.1623418109328747 0 +0.04987847943649638 0.1621571764958711 0 +-0.01868328753971024 0.1652612013823387 0 +0.0223159468824316 0.1500042105341574 0 +-0.1447851384100322 0.1299798204348352 0 +-0.1217829743622539 0.147633751209804 0 +0.08286000778307669 0.1613434833206795 0 +-0.0819973284921542 0.1145611877230635 0 +-0.1456871408982847 0.1152831746977703 0 +0.1458520403968852 0.1657179600643559 0 +-0.01872342129451407 0.1143976574476193 0 +-0.09167999148248637 0.1859492944606259 0 +-0.02277347747220715 0.1407188606253628 0 +0.1014467459397691 0.1397593006424555 0 +-0.03580854323707985 0.1359033390121545 0 +0.09325586245391307 0.1141275810227547 0 +-0.08379422823753477 0.1366056577722808 0 +0.04513208883000774 0.1383678292448149 0 +-0.1089100625515707 0.1642349698741388 0 +-0.06345067296050406 0.1358718534222296 0 +-0.03236457266662836 0.1135163698970095 0 +0.06930673428062722 0.11385582246619 0 +-0.0959243957385367 0.1605476677854742 0 +0.1254049650529848 0.1491074038911596 0 +0.09470539716936779 0.186796081948165 0 +-0.1050418989234957 0.1870834958968242 0 +-0.1282040335838154 0.186517143257822 0 +-0.03650030191728971 0.1870172131032865 0 +0.03657296127075361 0.112900166386923 0 +0.03659473598540912 0.1869941344721434 0 +-0.1268402162649714 0.1331422600380911 0 +-0.1224208314720774 0.1125269688935813 0 +-0.04638799260971344 0.1685714324931776 0 +0.1127568360204797 0.1323907250930302 0 +-0.1466093795389047 0.1872878171403562 0 +-0.1469526159968807 0.1484132366449746 0 +0.1327008836347958 0.1654882955043402 0 +0.1296388008244687 0.1126359270530643 0 +-0.01384387540859306 0.1313503859096144 0 +0.1472586013253707 0.1878034663588918 0 +0.1062206875279223 0.1125086754105542 0 +-0.05556995558704419 0.1262382256988755 0 +0.05326099197532391 0.1287911358201289 0 +-0.1477547166971063 0.170716888414528 0 +0.1472200815843241 0.1120594999433147 0 +-0.08713595022976416 0.1703454718242393 0 +-0.1270286028993725 0.1733489342174679 0 +-0.006120543249796834 0.1875814392047881 0 +0.1481006252199125 0.1484717046204251 0 +0.07661397642900769 0.1713308934198399 0 +0.128269367804591 0.1244881225386601 0 +-0.1316340022751435 0.1545950904115224 0 +0.1486142156959073 0.1272803493793752 0 +0.06277370831519827 0.1561784833922405 0 +0.1333297214307539 0.188687098761608 0 +0.08316821356133838 0.1885441398001342 0 +0.01530607148441484 0.1889089680606098 0 +-0.07077462228639116 0.1115656371906013 0 +-0.09959964227102022 0.1113679743784239 0 +0.002089818555675744 0.1724767124295614 0 +0.08986165530370258 0.1276791042226526 0 +-0.03676126389069673 0.1599775904489703 0 +0.03813025884313651 0.1613541030958488 0 +0.04763703866807569 0.1116410432513288 0 +0.04779525972864183 0.1892239150182142 0 +-0.001070547065664129 0.11119324159854 0 +-0.05116978744656354 0.1105462842376911 0 +0.01359144720868225 0.1416227717559284 0 +0.0138304654207165 0.1584411127516282 0 +-0.06019710818798714 0.1576300256874755 0 +-0.1210848160676562 0.123334675942058 0 +-0.07398276692323646 0.1897398460151 0 +-0.1035699659168409 0.1282811926826886 0 +0.1491072011560408 0.17651347487824 0 +-0.08609046931638259 0.1247263799093925 0 +-0.07348371658189956 0.1400849349581242 0 +-0.02308678352386716 0.1538497206539166 0 +-0.1354677315163347 0.1119150982593879 0 +0.05164446929364054 0.173105319973618 0 +0.06549315903435342 0.190011597628111 0 +-0.04330016691440257 0.14746509331347 0 +-0.05789605480085744 0.1481639388769616 0 +0.113222658849478 0.1898829847858229 0 +0.07428931486262333 0.1290036542075423 0 +0.1331836389622838 0.1407987134517236 0 +0.00253338089609681 0.1282744071216817 0 +0.06509164479447833 0.1422765672456381 0 +-0.07172074018504021 0.1719415690020075 0 +0.1009496639509016 0.1539227558126709 0 +-0.07732417147786325 0.152562301484541 0 +-0.05471480482021919 0.1898832855536177 0 +0.1123170005236121 0.1603090226613434 0 +-0.1315597977211434 0.1661572872821739 0 +-0.01983658824419013 0.1744047047157866 0 +0.092702560213564 0.1606785025021094 0 +0.01885137826266227 0.1097481522113305 0 +-0.04467277950924795 0.1292931888298588 0 +0.08385090170250661 0.1102789649166461 0 +0.1286902784050759 0.1751387555615896 0 +0.1103226251665275 0.1723230900415512 0 +-0.108409644673759 0.1394758691414233 0 +0.09930848322180642 0.1741830579034483 0 +0.07089941314642167 0.1599255021656708 0 +0.02223565756771862 0.1279065423974994 0 +0.02223565756771867 0.1720934576025007 0 +-0.003396303648677676 0.1468950323759592 0 +-0.09804649142363771 0.1474693219300143 0 +0.08314768578847544 0.1466274723419995 0 +0.1250191672558836 0.1592319434715895 0 +-0.1499107842387992 0.1385442659571854 0 +-0.1170074700612573 0.1721194391052792 0 +-0.03554760174101972 0.1253004113167126 0 +0.06637232935621031 0.1771920106109266 0 +0.01481852057811437 0.1790898671606125 0 +0.06475879789024522 0.1223108040769426 0 +0.116345521779672 0.1400452457309725 0 +-0.1375477735626417 0.1894391941694731 0 +0.1347828505117674 0.1318666125088007 0 +-0.115917672500457 0.1551458501209521 0 +0.09140082158496468 0.1395935277970211 0 +0.04701124601355166 0.1530523589181116 0 +-0.01572712546072275 0.191055264099432 0 +-0.04156641502919869 0.1097329374327716 0 +-0.05632873332230452 0.1781614732812506 0 +-0.1139715853799248 0.1902854221285106 0 +0.1381714933281383 0.1092197017480648 0 +-0.1083157210777495 0.1758301684673316 0 +-0.06420180815810145 0.1258078821840489 0 +0.1505615989394611 0.1578343650805442 0 +0.1038428947864776 0.1903870964498842 0 +-0.01165043155507919 0.1402777605858055 0 +0.05737465910916623 0.1380661053087607 0 +-0.09032790662424232 0.1096598987155875 0 +0.03138711419092113 0.1248057588481223 0 +0.03068685126708917 0.1746302766395521 0 +-0.08629555792495164 0.1603553362935616 0 +-0.08324491670843602 0.190552342923503 0 +0.07364210622896336 0.1372205788064733 0 +-0.150645362463263 0.1568598422398685 0 +-0.03923386483421567 0.1784364761324995 0 +-0.1512719227211612 0.1229386032070728 0 +-0.01032281047552493 0.1088780641856381 0 +-0.04591402966517297 0.1910957772573565 0 +-0.02829260271380514 0.1612779038095901 0 +0.03005025906191933 0.1086861546571222 0 +0.02832341577013502 0.1912020144450471 0 +0.1212047007557261 0.1087078422907414 0 +0.06110854236241791 0.1092126031740045 0 +-0.06898502874548405 0.1573376223471215 0 +0.1094869329566315 0.1229735617142383 0 +-0.1351640814707113 0.1296638400188053 0 +0.03628583500103515 0.1408898637853535 0 +0.006743584094975974 0.1376449540472691 0 +0.006438765855122613 0.1619536014148892 0 +-0.01042622784148846 0.1672742788647949 0 +-0.05428219218232677 0.1648651500512447 0 +-0.1193999440447606 0.1390389313751429 0 +0.02955453697548059 0.1542304736548849 0 +-0.1516159203511138 0.1791340225667286 0 +0.01531791227473752 0.1226134087656952 0 +0.1181468591179429 0.1758093301258933 0 +-0.09178928357182245 0.1304422806980033 0 +0.1197769513733269 0.1269412259707217 0 +0.04837950893017797 0.1196704249824557 0 +-0.0289432521754859 0.1912612121173636 0 +-0.01832156369829862 0.1229547113986465 0 +-0.1147844207142839 0.1087586329829333 0 +-0.01035045905011077 0.1581132046917669 0 +0.05671518929682653 0.1914889183984094 0 +-0.1387433882572086 0.150512021617176 0 +0.08098286772440293 0.180254616355647 0 +-0.1411862671236905 0.1223872684758966 0 +-0.02557283821238238 0.1089159972098179 0 +0.1513365270689077 0.1402740280196941 0 +0.001369724410822473 0.1911546512553355 0 +0.07530129135017824 0.1918673151955133 0 +-0.15167609839329 0.1080907864089812 0 +0.03584570504248109 0.1322497246206331 0 +-0.08096797739488439 0.1447172887120676 0 +-0.03022840725430865 0.1795344500069834 0 +0.04682568850932635 0.1804988682438745 0 +-0.090921216613216 0.142497330691356 0 +-0.06265938435251234 0.107913712627625 0 +-0.09795784105202704 0.192268291710072 0 +0.02885696716404428 0.1450951926406924 0 +0.09663702717469078 0.1330245989004809 0 +-0.08744222704433242 0.1787198339566477 0 +0.1516481330007766 0.119553019063269 0 +0.1256683329518272 0.1916002896970677 0 +-0.06991256221738201 0.1195581792235453 0 +-0.005848713388259423 0.1293887557187837 0 +-0.1138968169203497 0.1456009285981864 0 +-0.02615123810555944 0.1184430000841987 0 +-0.002615233056799882 0.1804934660523811 0 +-0.1280009399479909 0.1415178797612418 0 +-0.0529467312564383 0.1191024488569445 0 +0.07583700939505687 0.1081163151791922 0 +0.02032259885171749 0.1644053465213123 0 +0.02026199705424258 0.1357495800832428 0 +0.1402943041774941 0.1459211204541599 0 +-0.1036536574693328 0.1577028878117764 0 +-0.1395495376033342 0.1700875859192831 0 +0.00127402738059689 0.15504662251839 0 +-0.1110057434528547 0.1239398872734944 0 +-0.1029464417322485 0.120108669836541 0 +-0.01573944502521284 0.1817770276661282 0 +-0.03064674560380962 0.1426430115463556 0 +-0.1221478076498476 0.1921818435524437 0 +0.09901836691333255 0.1076900690376242 0 +0.05812959091759191 0.1629302951797622 0 +-0.0622534920189666 0.1924822370311014 0 +-0.0709665120054104 0.1800572982596182 0 +0.03604833965881589 0.1687448642081259 0 +0.07306179375213945 0.1209688997375001 0 +0.007499999999999995 0.1077368686691935 0 +0.1406427195698608 0.1922827141078096 0 +-0.02840248260485802 0.1345847444483248 0 +0.1126276590023601 0.107719793481936 0 +-0.09856222227722679 0.1817765659100344 0 +0.09374817332389031 0.1683806684445283 0 +0.04402546354615045 0.1674024349917564 0 +0.1189173161595462 0.1538136052341094 0 +0.1384763488620492 0.1704212847158504 0 +0.002088775049806575 0.1195151640692386 0 +0.05472361444649063 0.1555538554230337 0 +-0.106899458401384 0.1075759194791957 0 +-0.1419703356136378 0.1370335467125052 0 +-0.07798925066914345 0.10777525553406 0 +-0.1013147362742125 0.1662739963919465 0 +0.1011273744125872 0.1180301422288619 0 +0.0858066649188907 0.1540797286423403 0 +0.08423244111422137 0.1693008026029108 0 +-0.1421962706158793 0.1074771834191143 0 +0.1386897821776967 0.1612130526239959 0 +-0.07925993304226281 0.1715200158239101 0 +-0.02533814981831092 0.1687539963979032 0 +-0.1523845366438731 0.1305610866166966 0 +0.08896093209261398 0.1200342456326868 0 +-0.06472638205405214 0.1756739583291015 0 +-0.1287304920764336 0.1080242266382557 0 +0.1047106997223872 0.1325303823293925 0 +0.05932069161539803 0.1726091649084626 0 +0.04409203385327186 0.1459323706227946 0 +0.1522018024642572 0.1696586448052409 0 +-0.152617614871851 0.192730594391027 0 +0.09946096797154451 0.1468685390114845 0 +0.01520977590809289 0.1498253915667066 0 +-0.1234720341951268 0.1550960702258889 0 +0.1089999073139343 0.1428657349719324 0 +0.04578494665237293 0.1305943875129166 0 +-0.1523299708379007 0.1644507243989792 0 +-0.05603988447906456 0.134577545887591 0 +0.1412127720761928 0.1279694443348975 0 +0.1528083394678282 0.1928083394678286 0 +0.08987657749712716 0.192599685556695 0 +-0.02085668011686993 0.1332195617173715 0 +0.07847102007545113 0.1547586388764963 0 +-0.0175222373821744 0.107035730497028 0 +-0.01937327417769948 0.147106066312839 0 +-0.08903965191043382 0.1170005546884394 0 +-0.04201172818045124 0.1547957591731175 0 +0.1531555975391921 0.1822351590130155 0 +-0.07845278553075569 0.1212329106573316 0 +0.05407141983767121 0.1073645656292586 0 +-0.07702662580861583 0.1335672584177746 0 +0.009053636446149021 0.1926512692873005 0 +-0.09388796106650811 0.1674330200627901 0 +-0.04263027206758373 0.1391843036467223 0 +-0.06322607996220293 0.1431350157362511 0 +-0.1239907339207872 0.180975942680019 0 +0.08255780158740861 0.1293145653666417 0 +-0.05016226715796506 0.1740856161939313 0 +0.0886648466273125 0.1822774225591355 0 +0.02263776133378092 0.1576882615814306 0 +-0.06844741588535344 0.165397587666482 0 +0.04117904858214863 0.1072185184278017 0 +0.04117904858214837 0.1927814815721984 0 +-0.01229446372621737 0.1178612268019101 0 +0.09046424856604587 0.1072564675029908 0 +-0.1310102438263211 0.1798927609113145 0 +0.1307597153966495 0.1534729282961661 0 +0.1300688202651291 0.1822352211359661 0 +0.1530509600340251 0.1069490399659751 0 +-0.1529165479020684 0.1156893086693746 0 +0.09897563755683754 0.1813488086289302 0 +-0.1168222993132922 0.1176348545622166 0 +0.02097129412369452 0.192462767935278 0 +0.1530626504717858 0.1331064716731651 0 +-0.09334792937382354 0.1539864486140337 0 +-0.06990834926455912 0.1327738175815139 0 +0.007684657040736925 0.176857663376314 0 +0.1139289448505133 0.182195743108492 0 +-0.09013569003702225 0.1930142076514048 0 +0.02175047276060757 0.1428360547446258 0 +-0.04458665000467375 0.1617142389677874 0 +-0.1291400271761135 0.1147001142958453 0 +-0.1069293694382887 0.193179768984569 0 +0.06010616021548377 0.1274663871701799 0 +-0.03817496222404004 0.117964587277701 0 +0.09742640696059973 0.1933583136833055 0 +0.1244437316510347 0.1179020982622702 0 +-0.05001028558491666 0.1490901196200995 0 +-0.1312591627868585 0.1478818363673579 0 +0.06780882651742823 0.1066884501463905 0 +0.05103114495963539 0.1421981145750113 0 +-0.03434383108680794 0.1068636323354888 0 +0.008110620996883196 0.123489318912437 0 +-0.02163109775514234 0.1927237050880266 0 +-0.0263315632493311 0.147844407805375 0 +0.04188153034431879 0.1177023381890896 0 +0.03611529711748833 0.1801574496400351 0 +0.03188932428975958 0.1171117475791906 0 +-0.1156902096842112 0.1625357967394538 0 +0.1445511770421309 0.154141660160807 0 +0.1406985142715787 0.1852147504692712 0 +-0.1312714107739923 0.1930257242143598 0 +0.1324629763970991 0.1187332295737527 0 +0.133126339361794 0.1067482099733534 0 +-0.004923714186411344 0.1714861443250454 0 +0.1236603077930821 0.142171420038129 0 +-0.006135384243294542 0.1541631217790736 0 +-0.1531037845636897 0.1448076507990382 0 +-0.128183939057443 0.126187506690514 0 +0.07673097502591356 0.1151530710633164 0 +-0.03918187870972893 0.1675521818164781 0 +-0.1444112649997983 0.1810553384728403 0 +-0.1442335452943653 0.1937328330711885 0 +0.06158144285258178 0.1496441082887707 0 +0.003442955619531974 0.1442106983721352 0 +-0.1336302916404135 0.1731541477087967 0 +-0.1329034030339634 0.1364831265673049 0 +-0.1203900550130257 0.1306984078643197 0 +0.1261111857050192 0.1675621385593273 0 +-0.03934589727983365 0.1931288050268244 0 +-0.1102189438376142 0.1830810055972518 0 +0.06447324554120057 0.1160904289903721 0 +0.07120289681111341 0.1760079907813669 0 +-0.07436723610378619 0.1466678672366637 0 +-0.01154135658837496 0.1246424331937167 0 +-0.03749312363323103 0.1436366218539447 0 +0.0342091095034547 0.1071310141188149 0 +0.03344141901919781 0.1925735689371586 0 +0.1186456967693693 0.1930915551268966 0 +-0.01695964375333709 0.1566830171370698 0 +-0.01084733655600861 0.1925900587797467 0 +0.1185688690363508 0.1470157265370008 0 +0.09562417409837111 0.1224787229435494 0 +0.0776367137354909 0.1443076518192444 0 +-0.1432948466418325 0.1443497500557929 0 +0.08901800918668822 0.134280671533424 0 +0.1189416178666475 0.1612708646287229 0 +-0.1069727667174911 0.1335801126558635 0 +0.1448162176884615 0.1065077104772721 0 +-0.1535578271176705 0.1513803912280798 0 +0.01775641811258715 0.1167617209121246 0 +0.1338822574650611 0.1482475750631576 0 +-0.05560436485254231 0.1066125815573222 0 +-0.0846811638880865 0.1072461523894147 0 +0.03013375892607816 0.1839442775598165 0 +0.1534547811295207 0.1530600894263668 0 +0.1178254148373043 0.134769908679593 0 +-0.1534492150884094 0.185045974608564 0 +-0.04263031139657724 0.183263720872588 0 +0.05089699134618238 0.1352589820076518 0 +0.1452812692803823 0.1180309976158486 0 +-0.1524699323532077 0.1731676194306621 0 +-0.09187085782958196 0.1755022863088596 0 +-0.0687769364074178 0.1933653914541059 0 +-0.1005080907921181 0.1427395119538911 0 +0.1125882753399769 0.1142401637667279 0 +0.1348656702007348 0.1249523853147281 0 +-0.1219070719427644 0.1062314330652611 0 +-0.08328938188035606 0.1839013740753517 0 +-0.05566219797323586 0.1706148100844131 0 +-0.04730358481481906 0.1063252505958837 0 +-0.05764263376300059 0.1835740022500917 0 +-0.1454291080469327 0.1539694793609255 0 +-0.0549135249457674 0.1538027331322631 0 +-0.04855564380045271 0.1251027111078241 0 +0.07148829361734356 0.1673656954628365 0 +0.044012512644516 0.1849191120718975 0 +-0.1374627764561929 0.1162605907033354 0 +0.08810351555299276 0.1645266222195148 0 +-0.09581859615769156 0.1065224483661344 0 +0.1077859731131671 0.1072923439832629 0 +-0.1266483362844634 0.168270172873975 0 +-0.05698527080411472 0.140919823780149 0 +-0.03195487422520484 0.1569635073079511 0 +0.07805345622268975 0.1647478883592773 0 +-0.07799947738116483 0.19365170453926 0 +0.105898112191497 0.1486406879081937 0 +0.02233158858047041 0.1049304415190014 0 +-0.07565554232627626 0.1152191410693928 0 +-0.1476560587541098 0.1652317777242205 0 +0.1536869030912714 0.1626421619151412 0 +0.06902875995476633 0.1275870309436923 0 +-0.08444090614870134 0.1657156779996012 0 +0.1088572588993039 0.15461323191938 0 +-0.128469453950009 0.1598863894778311 0 +-0.1360057833514308 0.1592306592811952 0 +0.05448365788443854 0.1676043209793484 0 +0.1097634764132716 0.1940121747312318 0 +-0.03420379402983173 0.1301566537710278 0 +-0.02696513686675168 0.1757832109575556 0 +0.05352442771659979 0.1228401031075922 0 +-0.1364067362426863 0.1848729419210126 0 +-0.12060185874076 0.1756609701080143 0 +0.06752463277191473 0.1840104600451165 0 +0.1255868762344914 0.1061967660585693 0 +0.06977407461591498 0.1936672208698938 0 +0.008839185196183465 0.1559723898827883 0 +-0.1092623317968952 0.1588576914382051 0 +-0.05856958087644178 0.1221445055160307 0 +-0.01020187180904996 0.1833995317983874 0 +-0.1203183681284541 0.184777426347568 0 +-0.113871631391023 0.1378110336447623 0 +-0.009232254286786892 0.1344529411581896 0 +-0.005142922739967049 0.1062712170364778 0 +-0.0306728152853657 0.1201423245567826 0 +0.133220463789424 0.1593559315985443 0 +0.1466300878777804 0.1931569903053327 0 +0.002043057581498624 0.1664051825997614 0 +0.07041132223985684 0.154001776372951 0 +-0.06249749237227974 0.1512690192976935 0 +0.1286767212471076 0.1305609202472278 0 +0.09432582410475068 0.1785977673368633 0 +-0.09587106747371624 0.1148461952894993 0 +0.04541334511481195 0.1587551635657417 0 +-0.1065922817204736 0.170091624941624 0 +0.1540820845163803 0.1130834924427712 0 +0.01131452154049118 0.1828749414365141 0 +0.06623024038678653 0.1612233720052457 0 +-0.1253039577763355 0.1201878708184382 0 +0.1138121296323348 0.1663213292580905 0 +-0.1435494304213173 0.1744573406084883 0 +-0.01415464744694517 0.1718768363875095 0 +0.1059898205574291 0.1752224529892562 0 +0.01968759613420035 0.1834190388707293 0 +-0.005079941996228863 0.1144138500696908 0 +-0.08947302712473881 0.1351198587331285 0 +0.1464025855997175 0.1805282171892989 0 +-0.0505390292410141 0.1938618581327919 0 +-0.00392453243142647 0.1939366893541278 0 +-0.05068829485234033 0.1319395925452948 0 +-0.06822001927885821 0.1058883636436051 0 +0.09624703861635205 0.1546521212340821 0 +0.1540126930310342 0.1453366839449212 0 +0.02802333908723085 0.1299315954299937 0 +0.02867682258394571 0.1696408637709871 0 +0.08629300671220465 0.1417398664065248 0 +0.01272597722555713 0.1052320461411553 0 +-0.08006225600262348 0.1575542681790248 0 +-0.03102934343648428 0.1858988932889972 0 +0.03673906139357225 0.1564944602430518 0 +-0.0605799921391072 0.1316206578286411 0 +-0.04599374890872842 0.1139239418856784 0 +0.1089097123728236 0.1366228013478384 0 +-0.09974292341171333 0.1532180478183842 0 +0.05042044861490602 0.1942038936654087 0 +-0.0981337703437954 0.1309259218897725 0 +-0.008542776077249001 0.1451183725729693 0 +-0.03256439550213577 0.1647832252420857 0 +0.1440993492858015 0.1711362059786904 0 +0.0812540364206968 0.1931949561429267 0 +-0.01850940497147911 0.1377623136715286 0 +0.130338637530175 0.13541878654721 0 +0.002922881861217468 0.1044456406650344 0 +0.006579281506751964 0.1320481640593884 0 +0.0616493478551612 0.1947909163168234 0 +-0.1033784593059738 0.1805726084260928 0 +0.1451603912068627 0.1418938700489266 0 +-0.04435246754426647 0.1746045124857689 0 +0.1324999999999999 0.1945893555727858 0 +0.03624177145122837 0.1227926435774914 0 +0.1482387667387736 0.1326521434819188 0 +0.02056097675317603 0.1777637412694541 0 +-0.06278700532115633 0.1629877067924409 0 +0.07091429170297883 0.1332389408251824 0 +0.07009737229198269 0.1448558424680787 0 +-0.001083633186734282 0.1859969505925071 0 +0.009822430926033177 0.1442861431911585 0 +0.1532523773362492 0.1250318680630805 0 +0.1373180331910418 0.1369435387335879 0 +0.1230672932671217 0.1744530275610129 0 +0.1083974463508304 0.1867515030740028 0 +-0.04185078468763521 0.12478613182343 0 +0.1452682334649246 0.1599585931165239 0 +0.1334797014626686 0.171962210552034 0 +0.04837748534720736 0.1256680995508268 0 +0.06313511101636442 0.1375381996549319 0 +0.03168744448027492 0.1495091253367156 0 +0.01718406067265424 0.1725985757450395 0 +0.08066637678793293 0.1742207985950879 0 +-0.07865930063568713 0.1287210211811206 0 +0.1005616758511921 0.1588088540895786 0 +-0.05696584205281417 0.1123916744295586 0 +0.0493110494696228 0.1476571051659598 0 +0.1369588616238975 0.1158936617372365 0 +-0.06856365140299332 0.1435514625033601 0 +-0.08646717419945396 0.1320701526876741 0 +0.02302401424300893 0.1121598731719433 0 +0.02077786235687787 0.1222963865347116 0 +-0.07803110973726929 0.1851734980627226 0 +0.05952141918852855 0.1432805918945638 0 +-0.06674614539845981 0.1151970296775297 0 +-0.08939320029144285 0.1649694700067508 0 +0.07844503625419581 0.1349730304700399 0 +-0.05775679126288059 0.1950027723478013 0 +-0.1158370698006125 0.1261898328277802 0 +0.1109536186073304 0.1782463779805097 0 +-0.02319871598778671 0.1598013944046685 0 +-0.1017522928245965 0.1054919489519819 0 +0.006821676027987662 0.1696389797931333 0 +-0.09293549244873844 0.1803754085035315 0 +0.03298749736003883 0.1614480779261101 0 +0.08012219987741494 0.1851518566364209 0 +-0.1048888244136473 0.1151407782375083 0 +0.05324372124258493 0.1867515985435989 0 +0.01214845419232681 0.136675383027863 0 +0.08587938056748429 0.11580986481795 0 +0.05312784694761127 0.1122713775235612 0 +0.01173353372234787 0.1633616073733291 0 +-0.1416928481264344 0.1861003492786534 0 +-0.03359986340243778 0.1944473316697024 0 +0.01453962187811236 0.1942923523454602 0 +0.1060237660352124 0.1184032916910002 0 +0.04736783664891113 0.1038731549726025 0 +-0.1371591195753256 0.1051556378214176 0 +-0.04986526780666244 0.1871113246278279 0 +0.04142124905040841 0.1542020024291102 0 +0.02356949051420863 0.1880769784274102 0 +0.1083824065616287 0.1640277482347206 0 +-0.1138325202040057 0.1757587802871009 0 +0.05543970274514545 0.1765860980649725 0 +0.0707005335793693 0.188111266410449 0 +0.0670014136123471 0.1720380265542055 0 +0.1156984662730018 0.1238076106900458 0 +-0.06861170770344614 0.1875040263345522 0 +-0.07245734671712745 0.1533251493752247 0 +0.05992777881556669 0.1336159151119736 0 +-0.03899597256462077 0.1315748616662402 0 +0.0619344793111899 0.1849004777154228 0 +0.1546166227737392 0.1777383734562633 0 +0.08566819010613348 0.1246413209167621 0 +-0.137656400853437 0.1646840583369183 0 +-0.09066183783549427 0.1256430695875251 0 +0.004398506044866553 0.1124449144831266 0 +0.135600185639238 0.1833239878401331 0 +-0.08405748355684831 0.1197710485468661 0 +0.06835910894187994 0.1494872764602163 0 +0.08095838503359198 0.1055087479857728 0 +0.09524401612155435 0.1276980121498947 0 +0.1057379115183965 0.1693033695211912 0 +0.0394913634219319 0.136246114837011 0 +-0.04757534083187722 0.1444167574213905 0 +-0.09856607675304395 0.1257811686344724 0 +0.02567963945513414 0.1765055146873701 0 +-0.03793275899133761 0.1508590482210796 0 +0.143891793280213 0.124455837280398 0 +-0.1174263850364806 0.19486846813567 0 +0.1192421886766042 0.1876454641808821 0 +-0.0276872374697781 0.152106792947108 0 +0.04576120807806875 0.172480726200946 0 +0.1549971881915763 0.1871953329042457 0 +-0.07868662361140175 0.1390196133904609 0 +0.04161037438548653 0.1123745839646583 0 +0.05948787343416256 0.1221471098458045 0 +-0.05495160867903632 0.1591049538970757 0 +0.01232393414975129 0.1113246933132804 0 +0.1282713750341372 0.1441165487652746 0 +0.0007756867194746522 0.1328394266248887 0 +0.01844751711477159 0.1539867825547951 0 +0.1061699274288009 0.1271259715109419 0 +-0.07477294582841972 0.1576516865596 0 +-0.0298469073045825 0.105529022220899 0 +-0.1265043072648724 0.150634167502263 0 +-0.1031383385866243 0.1372785297708839 0 +-0.1131341929774987 0.1502754518992527 0 +-0.1025704071028053 0.1956117284407511 0 +-0.1470963907556125 0.1047700196844017 0 +0.09690731861709061 0.1634588984220699 0 +0.003134853871598244 0.178212302312043 0 +0.01721911311378079 0.1277497968788026 0 +-0.1553127468319468 0.1273740879548189 0 +-0.08312581156340981 0.1527015569910237 0 +-0.04667824183729421 0.1359221433255522 0 +0.1422220007524345 0.1134569796965772 0 +0.08735812542408 0.1588697680755784 0 +0.02598441876222879 0.1239379478519567 0 +0.1170388947410223 0.1050128265375107 0 +0.07694884612549742 0.1246054815352424 0 +0.06918028868347846 0.13891582491015 0 +-0.06946833945350181 0.1377561545009692 0 +-0.0207560261921945 0.127914209411488 0 +-0.002276501152059214 0.1254395566492154 0 +0.1051216283814346 0.1604686586963838 0 +0.07747533261068229 0.1779843146346072 0 +-0.121462942001584 0.1674316233692231 0 +-0.01761532683265014 0.1521675051191636 0 +-0.1460176358429072 0.1202914833526869 0 +-0.1411503629698668 0.1124701091505155 0 +0.1150057868422093 0.1707362929636901 0 +-0.01367688087952359 0.1629602234199196 0 +0.1248120921823427 0.1786700373876574 0 +-0.09567230008478961 0.1426425277565861 0 +-0.09226749402090662 0.1470975906527255 0 +-0.07549579565913545 0.1680971952095798 0 +0.09722811352205245 0.1419695253259683 0 +-0.1552799565406695 0.1377508418786216 0 +0.08869421818817499 0.1464406534246201 0 +-0.01447995663315349 0.1449936829318966 0 +-0.1117945056160643 0.1687716088750675 0 +-0.02044383075345832 0.1796872982234708 0 +-0.08324412827025807 0.1749794934316094 0 +-0.004351650551917508 0.1420812959560803 0 +-0.07478511433971805 0.1763192653220227 0 +-0.03505310893952417 0.181900738456664 0 +0.07800267258241861 0.1495892015439875 0 +-0.03765554267455191 0.1725305758222681 0 +0.1277455331690548 0.1634659933576118 0 +0.1132922724747724 0.1551203398509651 0 +0.09972525461850923 0.168869012385384 0 +-0.0646519397177675 0.1203475009653999 0 +-0.07356010277143882 0.1051602742840499 0 +0.1331102668835177 0.1777579835700995 0 +-0.1402147433589128 0.1326923534250912 0 +-0.1089699414264444 0.1456437318227156 0 +-0.06656926035991534 0.1705035103811637 0 +-0.1273076146917022 0.1956534959476313 0 +-0.1364911594622243 0.1246206814026112 0 +-0.01304903741458601 0.1044552488574251 0 +-0.08635169388947846 0.1448080236688482 0 +0.1026969733811739 0.1844750309129648 0 +-0.01880002978952725 0.1697375094391091 0 +-0.01799529172687121 0.1961881917091589 0 +-0.06456174637250084 0.1553447330759421 0 +0.1441567368245718 0.1762493618474919 0 +0.1280042995952538 0.1865693349060297 0 +-0.102865849128484 0.1478695869032362 0 +0.03616351533352357 0.1272266770759379 0 +0.04571776533593189 0.1945692274580078 0 +-0.05083609316646851 0.1696785487921538 0 +0.08935423109189898 0.1873997838671166 0 +0.00197953672857665 0.1494022076880114 0 +0.04934027416458445 0.1671346298662862 0 +-0.02765538533382489 0.1136336729370555 0 +-0.1489670328493412 0.1435559878074111 0 +0.1022548842105114 0.1954810278051675 0 +0.0814453277701583 0.1417950103200243 0 +-0.1376470430996972 0.1548329720034174 0 +0.1402579216884624 0.1325382406210755 0 +0.09132416857225538 0.1554689317971212 0 +-0.09708243560487864 0.1870690864543085 0 +-0.1375916046534369 0.1950626061853771 0 +0.1367544007056544 0.1037726738269836 0 +-0.02072226835831975 0.1883112196268483 0 +0.09508925373266276 0.1052177788452087 0 +-0.01096438101980304 0.1883855747502154 0 +0.08863947068549144 0.1123710455462852 0 +0.001788727790929942 0.1603204976684489 0 +0.1240392751876815 0.1542586137940695 0 +0.1208587114222928 0.1144147062588163 0 +0.06872150331706578 0.118664244845406 0 +0.1211726229424171 0.1218613054380448 0 +-0.1114760762678735 0.1050334888846759 0 +-0.1465516635009309 0.13481508046635 0 +-0.03759475398185925 0.1130025987868878 0 +0.0597211877074444 0.1678275339949411 0 +0.06090165319125095 0.1786221506733941 0 +-0.1183022829211358 0.1510425489453427 0 +0.005942624332596622 0.1885690877142142 0 +-0.007427000038445008 0.1634159212337738 0 +0.1140306954407237 0.1956584293098038 0 +-0.02197314279416921 0.1047067554283723 0 +-0.1460959315848475 0.1250953698319022 0 +-0.05334257315615296 0.1806981953416708 0 +-0.06155782278505669 0.1796161122656238 0 +-0.06950772885847123 0.1238423156073232 0 +0.0585473418626523 0.1056058456786826 0 +-0.08826826792633198 0.1548350746946667 0 +-0.04294963800819303 0.1049636985622867 0 +0.1235757435292146 0.1303519198862876 0 +0.04239434286189682 0.1798063121563736 0 +0.08937592706219412 0.1697191619796357 0 +-0.03114667968339152 0.1251065820789372 0 +0.0335319318466814 0.1366006661487592 0 +0.08617489085984945 0.1050158313564142 0 +-0.1186652708643243 0.1438057708527268 0 +-0.1549125982788526 0.1601629978914888 0 +0.09394624280962849 0.1738964240356833 0 +-0.05332997427029997 0.1441436164086296 0 +0.07205746180261854 0.104432948394361 0 +0.04085511595608395 0.1301902004824707 0 +0.03897123217530354 0.1454808817216408 0 +-0.005659928906641729 0.159207741155456 0 +0.03184287564114864 0.1126685946180018 0 +0.03637562111363827 0.1735339316993603 0 +-0.1247523266080256 0.1379676427762076 0 +0.1137510283047671 0.1451391344523433 0 +-0.0603281806988913 0.1876994175932168 0 +0.09863992835317847 0.1129933146943564 0 +-0.07196237369324927 0.162970913013532 0 +0.05966013914758837 0.1537032530447016 0 +0.09333550386180177 0.1451582907435723 0 +-0.1194613747520569 0.1589367265167298 0 +-0.08244091919155415 0.1957543335352384 0 +0.1554803367983268 0.1370479385167714 0 +-0.02317394923622082 0.1227834843058274 0 +-0.1117665493734682 0.1952964048535153 0 +-0.1146230127773811 0.1852568344578477 0 +0.1560667157796186 0.1576480880602932 0 +0.001685144696638337 0.1398462757631229 0 +-0.1325671578033973 0.188856722791586 0 +0.08570856766102591 0.1950336627074623 0 +-0.04987006438730263 0.1601558569388502 0 +-0.05870264561144463 0.1646764773636844 0 +-0.01561376664775245 0.1770468390416419 0 +-0.05989960712848812 0.1731244994100015 0 +0.05028205612588183 0.157147432646077 0 +0.01153431338971978 0.1736846085479868 0 +-0.1406562202350697 0.1274065555981903 0 +-0.1097092392724771 0.1873866382885967 0 +-0.1557767557075995 0.1041852149782404 0 +-0.1098764633775433 0.1111033937569512 0 +0.13764281518441 0.1957600697865576 0 +-0.1177654731093552 0.1044964449855124 0 +-0.04316108416919821 0.1957482185634606 0 +-0.1485284498370716 0.19561757604053 0 +0.01745671007414527 0.1682173875661127 0 +-0.06577559859890468 0.1312601524260656 0 +-0.002109019776598161 0.1755642484601069 0 +-0.1549149610322557 0.1198825873634442 0 +0.1182272135783074 0.1815794750884312 0 +0.01914195133910612 0.1468702826523463 0 +-0.1097770265565689 0.1292006529511719 0 +0.02633328339000793 0.1412219130995677 0 +-0.09115487187646631 0.1047963124873771 0 +0.02719999311549536 0.1043812787272218 0 +0.02702220466123889 0.1962069600010168 0 +0.02441927354555868 0.1677007759182421 0 +0.02439051513427296 0.1332677117125707 0 +-0.1562673934434945 0.1769336413888752 0 +-0.03718223009068938 0.1554246532178171 0 +-0.1316079904704927 0.1042149156012681 0 +-0.10402040763627 0.175560374611128 0 +-0.08624720611988348 0.111055714690145 0 +0.01197082067189792 0.1258522238384915 0 +-0.1295423145148751 0.1295686426468352 0 +-0.09433177388572711 0.1946671145039083 0 +-0.1467897370106529 0.1099121799380407 0 +0.1123997322402868 0.1183170791882331 0 +-0.09989239242057557 0.1169581820429475 0 +-0.0002382385855069195 0.1161258303889571 0 +-0.1147679928942614 0.121696512883036 0 +-0.09155974682769497 0.1592730169127485 0 +0.02685198930797546 0.1497631879380482 0 +0.1337941453194868 0.1115228733512095 0 +0.01416024038191305 0.1173526249106297 0 +0.1137440251313585 0.1367260778422336 0 +-0.04632593533262771 0.1525034387224611 0 +-0.05135421657112946 0.1044748161565628 0 +-0.1077939640851203 0.1203407896036485 0 +-0.01665531859122477 0.1184378506159416 0 +-0.1179900656664005 0.1130299627047919 0 +0.0278098130287664 0.1586587116829808 0 +-0.1461314283036173 0.1599983634726816 0 +0.07747085869458085 0.1600954790959205 0 +0.05771154862130975 0.1125899405017497 0 +0.0635387392122779 0.1048236605600975 0 +-0.08657134862837422 0.1875267398602263 0 +0.03376024240993666 0.1451543588477406 0 +0.09914766347060525 0.1885712124721058 0 +-0.1553383238025857 0.1121162929579247 0 +-0.01517149328932929 0.1109632033519606 0 +-0.02522574204607763 0.1798356033447827 0 +0.1229007332004378 0.1636885720636597 0 +0.05214083453018818 0.180483314631646 0 +0.1376374840441039 0.1656484038633098 0 +-0.1556792776437124 0.1682096498044976 0 +0.005740951219144605 0.1949551951304433 0 +0.1490105546817342 0.1043185230949786 0 +-0.00273020305006782 0.1671770488847572 0 +0.01790652816648637 0.1043500846375138 0 +-0.07379908287958131 0.1224624811343357 0 +-0.07254806047074749 0.1844436196640523 0 +-0.1210876184435342 0.1175879927323708 0 +0.141286921861275 0.1506195555840145 0 +-0.02761307706421844 0.1959487861130074 0 +0.1395570471827121 0.1412178687544798 0 +0.1042552826498348 0.144549076498193 0 +-0.1178680031723686 0.1342038816281117 0 +-0.03441521724456087 0.1764696529326656 0 +-0.137236524578975 0.1377403675792189 0 +-0.02351454056289053 0.1640710249710249 0 +-0.04106866693035446 0.1884325948786252 0 +0.1493505975854904 0.1623621723418994 0 +-0.1004745059929518 0.1615185678045816 0 +0.1558947315344933 0.1724490434557708 0 +0.1115042029100008 0.1278685756498725 0 +-0.07372179042379826 0.1956571281258516 0 +-0.01356822768360742 0.1548245783920308 0 +-0.04386037362244482 0.1786427176256485 0 +0.1557543649384705 0.1174760248718974 0 +0.1267808158147842 0.1391635322777276 0 +0.1160739411748117 0.1110009134399982 0 +0.08469162781426939 0.1840464850562306 0 +-0.02737840616823008 0.1393029305054884 0 +0.03223009120298698 0.1882367507732787 0 +-0.02107916091276955 0.1185327122664635 0 +0.1027736329981171 0.1043272367355195 0 +0.04582967670091617 0.1158497127575803 0 +0.1489737406208098 0.1529677393240032 0 +-0.1481619717672317 0.1751881930149676 0 +0.127656370824913 0.1955533517667716 0 +-0.06625179850915139 0.1800578311098538 0 +0.01652649444870382 0.1334708418567791 0 +-0.04107286813696323 0.1356787958681692 0 +0.06557993509820391 0.1104213196716069 0 +0.1255445187757959 0.1121456353564959 0 +0.05749999999999999 0.1960297578684142 0 +0.04152405172109738 0.1412908789660945 0 +0.03943539497850105 0.1658806477772736 0 +-0.02088847297117371 0.1102654470825739 0 +0.05219052014330568 0.1511353880149224 0 +-0.08151634727218537 0.1326547652359576 0 +-0.01427177479447335 0.1364338325171122 0 +0.03117071090264476 0.1407999242964413 0 +0.1409964922090256 0.1571844049464228 0 +0.1037267970790104 0.1222818959478025 0 +-0.1416217711475762 0.1177448808721157 0 +0.04027004990069626 0.1703043988157721 0 +0.05431559841547871 0.1599358507738236 0 +-0.04158562138037947 0.1153651490816807 0 +-0.03163072833281986 0.1379858475516953 0 +0.09329881131326179 0.1957524355123792 0 +0.01900141385781172 0.1596414894440247 0 +-0.1232227427387232 0.1426800782231445 0 +-0.008694551814523447 0.1716838623382271 0 +-0.1342979286354801 0.1516965896332924 0 +-0.1354343228850007 0.1472752947978768 0 +0.01250846680559073 0.1532603928644282 0 +-0.06706240158046249 0.1101505407830914 0 +-0.1492685736203848 0.1522853806623742 0 +0.0580782045892 0.1870320634073827 0 +0.05870965663676733 0.1580232675896516 0 +-0.1554322135185145 0.1555870498121213 0 +0.121766094346248 0.1039834869773643 0 +0.09215302936489737 0.131443448984476 0 +0.1007591575374743 0.1350104951607538 0 +0.1005466504318108 0.1302337952220908 0 +-0.02516051393002028 0.1313322039115164 0 +0.1162741574372031 0.1295430681682127 0 +-0.0188189355713304 0.1425494433287341 0 +0.07909393256262071 0.1112340946766309 0 +-0.09363296279237293 0.1900967643093388 0 +-0.1485175321396437 0.1835126528324957 0 +-0.1437437358968612 0.1682460250704595 0 +-0.06926321700724124 0.175806092637107 0 +-0.09469970445749412 0.1109563945109729 0 +0.1378962484473168 0.1883512470208438 0 +0.1421308032331502 0.1962189166935602 0 +0.07359340864172613 0.1962002641625535 0 +0.01069808313680609 0.1883841002018734 0 +-0.0948747723880671 0.1346358648084554 0 +0.1223619500110659 0.1954988167299246 0 +0.0520261041142421 0.117461008159027 0 +-0.1557613855564063 0.1889763725929361 0 +-0.02540943491029422 0.1883744764104795 0 +0.08564067647962838 0.178155876510392 0 +0.03103284360280233 0.1797034188178893 0 +0.03755047892920067 0.1042496941762979 0 +0.03727620355789756 0.1956235983297753 0 +0.0324517335036941 0.166576868688128 0 +0.09600408911937326 0.1375815846257469 0 +0.1557328412673052 0.1292593539965285 0 +0.07398005962914134 0.1561898664355519 0 +0.0711955745635067 0.1093756923985444 0 +-0.04887742166126238 0.1175937086251944 0 +0.02695403847421357 0.1142735174721233 0 +0.04884427796451661 0.1845087217586198 0 +0.1212117256250486 0.1385280084844155 0 +-0.08347155693002065 0.140933388780343 0 +0.04404455403358856 0.1217160563961658 0 +-0.1498782129127544 0.1277279774852229 0 +0.1368047239959325 0.1744048487839387 0 +-0.1023295490522642 0.1903394538691591 0 +0.147030446782045 0.1370974636978754 0 +-0.1307421536513229 0.1705906740015474 0 +-0.08791243538229224 0.1830114920730048 0 +0.03254745446122386 0.1295228813336053 0 +-0.08056541845959485 0.1490195644822815 0 +-0.07892026790432634 0.1894236150616692 0 +0.06385723766702323 0.1274585980365655 0 +-0.0331199033254953 0.189978803053276 0 +-0.1062234597722336 0.1243582363831637 0 +0.07264539156080677 0.125092579253528 0 +0.09522069998981224 0.1096639905787571 0 +0.004883732699113226 0.1538976751102776 0 +0.0461188921847359 0.1636135543152291 0 +0.09651039291100011 0.1180245571405284 0 +0.0544674748075313 0.1336753109639379 0 +0.09693672463646881 0.1505599100827757 0 +-0.1425480984095023 0.1495238277394799 0 +-0.007353072608664345 0.1389054113087779 0 +-0.03007183219924896 0.1681112126412085 0 +0.1241219786096567 0.1259226567136044 0 +-0.1272225417264613 0.1457493390587893 0 +-0.06250000000000004 0.1036924757408899 0 +0.1301901733424779 0.1491932258978513 0 +0.02402557483089397 0.162141147122878 0 +-0.07643836335920046 0.1433731011354299 0 +-0.09634072709132988 0.1769200198476114 0 +-0.01546073727208583 0.1267328710685185 0 +-0.03051030878305106 0.1098824935344204 0 +-0.1319620845871029 0.1256704978725603 0 +-0.104996084292469 0.1621441257586609 0 +-0.07416739024866269 0.1109225925001957 0 +0.007592254087285399 0.1275044662230806 0 +-0.1020994155651149 0.1705452064522752 0 +0.04885807987691075 0.1766551612269803 0 +-0.02580549935374562 0.1567829147617915 0 +0.02460039268885418 0.1462176153504136 0 +-0.1238290221068426 0.188171608006418 0 +-0.1318176625266008 0.1404576173923063 0 +-0.09271108914690414 0.1387301072148127 0 +-0.1072607693570081 0.1549633743963896 0 +0.04217030881268466 0.1497737276015176 0 +-0.1352428388354127 0.1691760793153953 0 +-0.1026798238488006 0.1325921158723349 0 +-0.03071009848303633 0.1748442039938786 0 +0.01632310954772399 0.1379379527172724 0 +0.0001435459357470056 0.1956053387937152 0 +-0.0622280740905214 0.1118606596941392 0 +0.06302220390921087 0.1638805939945429 0 +-0.0149399891383472 0.1672832781889111 0 +-0.07318542710378197 0.135701015473312 0 +-0.02661294635453503 0.1438329056728547 0 +-0.08747161289395951 0.1962819079281648 0 +-0.05655231142357603 0.1165968023860406 0 +0.006351853059945244 0.1199681696408895 0 +0.08247794800448117 0.1568382332485883 0 +0.0274813260719063 0.1864795895187659 0 +-0.1228922835949826 0.1720263606726417 0 +0.1561659113796538 0.1415317300962773 0 +-0.02420170558191076 0.1363694177427223 0 +-0.0347947856874072 0.1463168194182456 0 +0.1485375577187057 0.1228704142803943 0 +0.07588972618181471 0.1865843759149 0 +0.07914709347828862 0.189068528737979 0 +-0.04251229639287991 0.1708532799344037 0 +0.1558047704503522 0.1668439473870121 0 +-0.09720184499561668 0.1647465259023833 0 +0.04667318685038981 0.1424521074104087 0 +-0.001959005632259365 0.1298752650230102 0 +-0.01034809160427196 0.128700512577266 0 +-0.00721143926120566 0.1251685097320109 0 +-0.005852885295274196 0.1103753854587253 0 +-0.08160977812908893 0.1045011633351448 0 +-0.1560965407989167 0.1478291299139318 0 +0.07299071720543671 0.1166837403530621 0 +-0.1402627218006482 0.1820396128383792 0 +0.0635724366582623 0.1735078170643864 0 +0.07677766115974072 0.1038320500832066 0 +0.07194863931749744 0.1712177758929494 0 +-0.06537669493949512 0.196188693535943 0 +-0.02305396201739365 0.1145721655069552 0 +-0.04044104525447954 0.1629797868833262 0 +0.008432912308247019 0.1657842391846984 0 +-0.05258588573281001 0.1235029959003247 0 +0.1020837161135996 0.1780999946950783 0 +-0.1223763614756061 0.196540761527149 0 +0.07784092911768319 0.1394244001084789 0 +-0.02744749481711384 0.1226082953121169 0 +-0.05909286520614784 0.1371914503067876 0 +-0.02952844545065055 0.1303446165439098 0 +0.03718986758420619 0.1177479964325896 0 +-0.1557541672795071 0.1957541672795075 0 +-0.03789910935285054 0.1037653805709951 0 +-0.1184939522975766 0.1895437105737401 0 +-0.1119477859411577 0.1420271393501389 0 +-0.08164033309311604 0.1100868857681394 0 +0.09133112247973875 0.1236721606497463 0 +0.08676578314672592 0.1305297771233297 0 +0.1298409976195344 0.1912061127798674 0 +-0.06333514841535262 0.1472582491795199 0 +-0.006786410452635994 0.1794671506202919 0 +-0.005386970752066417 0.1834827585994297 0 +-0.06843631951305006 0.1832995356516064 0 +0.0827133886299575 0.1514804505362026 0 +-0.002379903752360121 0.1519019608984144 0 +-0.09904132812564581 0.1579840662069251 0 +0.0934660048247597 0.1828148675228591 0 +-0.08015224641841129 0.166620772789925 0 +0.1161114084587498 0.150472284407124 0 +-0.1560232480913099 0.1326117645876519 0 +-0.1561610143054737 0.1427732854616094 0 +-0.002617995645404348 0.1899689765644904 0 +-0.1273888096411993 0.1782330562425638 0 +-0.01927374834223886 0.184080629769747 0 +0.1431567053276149 0.1885908199676762 0 +-0.03870794807535791 0.1399515811373889 0 +0.003375210180493715 0.1236057808898017 0 +-0.0483322247726741 0.1650580258559314 0 +0.007499999999999995 0.1034645241567694 0 +-0.1163444188033847 0.166603449607361 0 +-0.1246024271100548 0.1292628392503301 0 +-0.1267589116511782 0.1118087315390947 0 +-0.1309940929253697 0.1108236641675561 0 +-0.137957388513124 0.1744268077738638 0 +0.04361765999717972 0.1341776516010139 0 +0.07709926019954265 0.1192739299909077 0 +0.1118991103400654 0.1036970487320395 0 +-0.07169822353997586 0.1152810707094803 0 +0.150601041107371 0.1155967157264381 0 +0.1494927350172576 0.1447423496879306 0 +0.1030194253904425 0.109733947930317 0 +0.155820245205183 0.1958202452051834 0 +-0.08805252486557914 0.1745047316216345 0 +0.06082920391128063 0.1897918065673698 0 +-0.0980789459665219 0.169071462815079 0 +0.1234813133355936 0.1880482203115418 0 +0.1211323162536976 0.1576929125332199 0 +-0.01002107544384431 0.1210131763572993 0 +0.06946486286561998 0.1228892901019388 0 +-0.1256389173527387 0.1042004152398731 0 +0.02869321727852418 0.1200887259290002 0 +-0.08871511031450853 0.1212393204126821 0 +-0.1015106631751335 0.1851950346745627 0 +0.1360855654579253 0.1450394828446984 0 +0.06587006300883179 0.1958468040701097 0 +-0.1507403123782335 0.188149306123008 0 +0.04345793363687431 0.189347734064194 0 +0.05156779148315067 0.1039409664216964 0 +0.09396751384834942 0.1909105075748268 0 +0.1291821863700672 0.1576891195920885 0 +-0.045649531339843 0.1862386857698882 0 +-0.1562665057766035 0.1812227277128336 0 +0.1482149821799398 0.1690885380738321 0 +0.1284134001658551 0.1202930422822767 0 +0.06959867050102844 0.1802229798465251 0 +-0.1331704866667967 0.1165892619890039 0 +-0.1135300657333752 0.1142506884331652 0 +-0.04537244673109761 0.1574537549814744 0 +0.01834644069178266 0.1961161887062677 0 +-0.1073172769084883 0.1035235974506627 0 +-0.09442737779991182 0.1265864954130823 0 +-0.0047250069948029 0.1335553583014191 0 +-0.1278082356006946 0.1825196184155372 0 +0.1417616228739316 0.1671856970343761 0 +-0.08755319299270772 0.1394656491771109 0 +0.08562772956657873 0.1731694840084878 0 +0.05476942498713606 0.1425871143211231 0 +0.0796115774676099 0.1686516330620553 0 +-0.01311352714536208 0.1962402164780351 0 +0.1418625223609236 0.1810050657831953 0 +-0.1223088287022011 0.1340523271553672 0 +-0.05910544869615632 0.1272922829126037 0 +-0.05310027306363577 0.1846671142838738 0 +-0.1493460687405129 0.1132369634366341 0 +-0.09912096909252875 0.121539671666416 0 +0.05641894939153258 0.1261781810316064 0 +-0.008280066903401809 0.1957281787603247 0 +0.01624177645251563 0.1627905408814499 0 +-0.0737076519238871 0.1310159267839049 0 +-0.05239804259267786 0.1149819000983539 0 +0.1212322830794575 0.1502696355287613 0 +-0.1247186665857342 0.1592609358753263 0 +0.1445369281256116 0.1297072713310869 0 +-0.001774031749798646 0.1036249326997875 0 +-0.04105922735868137 0.1587242972787488 0 +-0.1291195449714143 0.1371743738456938 0 +0.03904635828241616 0.1829977110543857 0 +-0.08392046167975802 0.1799929342092114 0 +-0.1453232360764349 0.1396852686721708 0 +0.08104805714042694 0.1161538435947906 0 +0.1100365545951535 0.1109644470455535 0 +0.03280148138773138 0.170807389924304 0 +-0.01543814000255786 0.186168207951793 0 +-0.09797200440811191 0.1965094269309463 0 +-0.07508545485611798 0.1810939928347604 0 +0.1446555080836064 0.1467706663083893 0 +-0.1422903561893635 0.1034805681849867 0 +0.009813918534624136 0.1404228252260949 0 +0.08815994042265142 0.1508564761950823 0 +-0.1342455239198281 0.1770876248706304 0 +-0.01222028326179069 0.1796186431465618 0 +-0.1499024876131095 0.1182649623798597 0 +0.001128122719163395 0.1822697109458142 0 +-0.09359342978395986 0.1633939401340294 0 +0.01867070350600333 0.1883093352737153 0 +0.1559778787421082 0.1040221212578919 0 +0.008157877318308413 0.1809445692082348 0 +0.04254504596064931 0.1034520453314315 0 +0.0557607950935055 0.1714460142353288 0 +-0.02261992999168793 0.149666260790974 0 +-0.1275545077682662 0.1907344229617101 0 +0.09242410306035152 0.1646756708482872 0 +-0.1040692619863678 0.1104305023579139 0 +-0.06971552307667661 0.1285893627872819 0 +-0.008702954126015598 0.1039209060159082 0 +-0.1317944729398172 0.1839172522948092 0 +-0.08675599227858413 0.1039070800785188 0 +-0.03875005777842683 0.1223825026817132 0 +-0.1499659906814007 0.1613676728362138 0 +0.1024882208989316 0.114340338014099 0 +0.09941493435233523 0.1214027536930843 0 +-0.007144426004367885 0.1501120017433541 0 +0.02269897303282342 0.1963014604396461 0 +0.08994554206621114 0.116289717080269 0 +0.1088102756908984 0.1313076911862151 0 +-0.06695292937935626 0.1619021610121652 0 +-0.0475290443253121 0.1771229442357644 0 +0.08232936382703658 0.1655461455619418 0 +-0.05410631297025114 0.1382460290633767 0 +-0.09085719312922493 0.113798234896286 0 +-0.03245669585518691 0.1610731116602455 0 +0.1318745054244674 0.1272321110193056 0 +-0.04711275682958099 0.1962995251688596 0 +0.07780566987471969 0.1965319363764019 0 +-0.08284663282187954 0.169836286373857 0 +0.1056655715856962 0.1400188105937891 0 +0.1409411928204159 0.1170197498561783 0 +0.01445903136972084 0.1457762592438433 0 +0.03583398579351282 0.1645539547381825 0 +-0.02984731907104479 0.1166783724555706 0 +-0.0004783715833634464 0.1438939368066082 0 +-0.1111608373551258 0.1729103598979041 0 +0.08120022488865304 0.1257025889074075 0 +-0.001636418950420706 0.1209763510703536 0 +-0.1511779912572074 0.1683553319545775 0 +0.08680030601672976 0.137697845521803 0 +0.06491369238306709 0.152508142271047 0 +0.1387524966645301 0.1247287703028751 0 +0.1369577027610258 0.1282145940169471 0 +0.04221467466335764 0.196656383570594 0 +0.1502135772021742 0.1959392440075084 0 +-0.1022476168897685 0.124278225951438 0 +-0.1040815775993531 0.1528152331490275 0 +0.03752504284213441 0.1089867661312867 0 +0.03750861664092569 0.1910491933338562 0 +0.1364023009264683 0.191934097049921 0 +-0.02605561590330791 0.1039127246840669 0 +-0.1474867470741864 0.1913424251726686 0 +-0.08207491423047808 0.1615878699117497 0 +-0.1513260306101761 0.1037638039072494 0 +0.1123500389805111 0.140279798869064 0 +0.04407513308035869 0.1267257019293531 0 +-0.06151362818971572 0.1963533203369125 0 +0.1562597105430338 0.1215282579212312 0 +0.1366968257061963 0.1581155172986969 0 +-0.1354670232674598 0.1339754728785988 0 +0.1519812965404388 0.1735122207538936 0 +-0.02829869595467891 0.1717051876754155 0 +0.1509241274191144 0.1890806207637176 0 +-0.04226418718010059 0.1431886603351452 0 +0.04988385779858949 0.1313669494075921 0 +-0.09115445552806406 0.1704969309275125 0 +0.1154679630050901 0.1855815319748816 0 +0.1413645884370768 0.1040364988166848 0 +-0.1194985596207015 0.1089773924308472 0 +-0.04557602541808675 0.1099312235222897 0 +-0.01700651680092152 0.1337177494801181 0 +0.008329270260229921 0.1116587626988869 0 +-0.06498538896537352 0.1395229341445178 0 +-0.1110771581713974 0.1348234041220096 0 +-0.1196020654473721 0.1544311891794604 0 +0.1090471633704032 0.1466625403680805 0 +0.01564846501176263 0.1135566257981196 0 +-0.03776288956643367 0.1967985155652398 0 +0.1166642174576466 0.1584908223025772 0 +-0.06475476714104335 0.1890971950605863 0 +0.1495194408732533 0.1843628894732355 0 +-0.02259204521839715 0.1449135988332517 0 +-0.02344369120298142 0.1720709495497493 0 +0.1292736878781318 0.1039274516267371 0 +0.03145591347707391 0.1962829103813189 0 +0.03145591347707389 0.1037170896186813 0 +-0.1305895955279537 0.1754810530601654 0 +0.01099967246365986 0.1961359616745464 0 +-0.071334055396338 0.1679116428470152 0 +0.1560304109449078 0.109602117437431 0 +0.1405339791851589 0.1740645036272132 0 +-0.1404063433905898 0.141202946185455 0 +0.1022110368592493 0.1494997521145351 0 +-0.1257185697171438 0.1159171051783315 0 +0.1294940613990281 0.1088628105699049 0 +-0.1119517087737064 0.1616615546870018 0 +-0.1127454258400196 0.1797474967432069 0 +-0.05372098810639427 0.196239433905431 0 +-0.1432234581074933 0.1633746959537184 0 +-0.1004236344028992 0.1779433134520146 0 +-0.01029485250079077 0.1135659150129725 0 +0.07882384307899225 0.1304186595670705 0 +-0.0554961540886163 0.1299438649583768 0 +-0.105149272662649 0.1662463062428418 0 +0.1091742069447334 0.1152628489247669 0 +-0.07741162351597822 0.1249762947875538 0 +-0.01750000000000002 0.1030737389775124 0 +-0.1413719599173106 0.1962840618293531 0 +-0.1280982179261231 0.155582937589385 0 +-0.03331824124400801 0.1033799984532832 0 +0.04475275528208312 0.1766561775658188 0 +-0.05426696371037351 0.1743202259356266 0 +0.150373053044271 0.1801977367607645 0 +-0.03466617673092364 0.1410540379467422 0 +0.1423631726652727 0.1629366232823601 0 +0.05288257617335021 0.13860270904111 0 +-0.1514349848243788 0.1342767838370527 0 +-0.1511531235197001 0.1482444545280802 0 +0.1568397821931704 0.1824827605879598 0 +0.1339665287644363 0.1518648317444602 0 +0.02435495366889336 0.153794327056812 0 +0.009781107222422805 0.1598667277525397 0 +0.07419249050552695 0.1124031226894893 0 +-0.07852326041664698 0.1752523072147463 0 +-0.07562284642700599 0.1724714809302913 0 +-0.006514509263685556 0.1748936745249836 0 +-0.1326040042382728 0.1965109080296351 0 +0.1560972268775854 0.1490901100553144 0 +0.005890484126568791 0.1736210808562086 0 +0.005500924357394824 0.1578429190578889 0 +-0.1484597199306905 0.1313776635158111 0 +0.06458034871949382 0.1811896470751572 0 +-0.07763182631393425 0.1034873386306509 0 +0.1374585651698599 0.1490745823166753 0 +0.1195346079983236 0.1714435113353074 0 +-0.1203241560336946 0.17957591110592 0 +-0.1421639967761732 0.1909506833707324 0 +0.04990342662739614 0.1078902125490734 0 +-0.07906252480915318 0.1172799786794067 0 +-0.05917684173614507 0.1441443891289547 0 +0.01128791642590154 0.1211980365755136 0 +0.10635994486628 0.1956661135976384 0 +0.09304259528612287 0.1351847663682298 0 +0.05751107017101218 0.1300167189188801 0 +0.1138956096628419 0.1751502868931898 0 +0.01094579846564106 0.1484456608404467 0 +-0.1372372217855323 0.1205054124418113 0 +0.09789823492497077 0.1776918737056804 0 +0.1104855917731826 0.1828925752694379 0 +-0.006840339386187215 0.1682074511293197 0 +0.03342575909360397 0.1534391536969535 0 +0.1156249092771256 0.1626865532995332 0 +0.1567251545729175 0.1921647835154515 0 +0.06842827778601893 0.164678264068585 0 +-0.1267710587582444 0.1636637154720218 0 +0.1354790037619105 0.1215097349494114 0 +-0.1383571929122331 0.1089234382561188 0 +0.0916623620539767 0.1035367311251836 0 +0.117670866182821 0.1969341597931863 0 +-0.1122609947095329 0.1189769692292533 0 +-0.1563957126862568 0.1637210811832419 0 +0.02034492045080903 0.131609474325977 0 +0.1351447394116588 0.1621690145327731 0 +0.1227577981796634 0.1459874330190099 0 +-0.1155562898323231 0.1416567607641915 0 +0.1193825417864307 0.1431478280436451 0 +-0.08401932096916685 0.1482591209759165 0 +0.03154851904938653 0.1329919600251721 0 +-0.0926455703939226 0.1182711629148005 0 +-0.03894599380438928 0.1274358121999692 0 +0.04898053918293524 0.1385379126841013 0 +0.1044177580660555 0.1366480098701831 0 +-0.01439779572851498 0.1220161722415476 0 +0.1494924554057812 0.108493863332172 0 +0.08481055364866455 0.1197095246352189 0 +0.004315961002037479 0.1167572136986206 0 +0.0341921808528635 0.1836722903862581 0 +0.1251424168251208 0.1220711934742656 0 +0.1057654697552489 0.152457543373893 0 +0.06265528857825615 0.1598378677243479 0 +-0.08829467936060895 0.1285009824833364 0 +0.1318618731812263 0.122807263240928 0 +-0.05117356772951162 0.1529520878515768 0 +-0.05403972072481684 0.1500068254586892 0 +0.04587550803135475 0.1492400549024299 0 +-0.03416941571883352 0.1170311016518395 0 +0.09024344773686746 0.1785545929359699 0 +-0.1522779967746828 0.1967915950407136 0 +0.02344861283284937 0.1380942674393101 0 +-0.112940317584608 0.1648986274247308 0 +0.1300200194772538 0.1691718421308523 0 +-0.04614636295593905 0.1405158400114079 0 +-0.002304379458849972 0.1571636258254429 0 +-0.08406689759425039 0.1566862235427387 0 +-0.1113101466612863 0.1548863781861959 0 +-0.08131325593165306 0.1247607967549012 0 +0.04494092721432231 0.1080108100920085 0 +-0.05876331720023942 0.1912669281314343 0 +0.1323555341211881 0.1150390847787149 0 +-0.05866276251411241 0.103597933526314 0 +-0.1221549304795541 0.1515666193915997 0 +-0.09819896357615558 0.1031335468793156 0 +0.08991308505305985 0.1432018173404123 0 +-0.105082592080025 0.1429333198716462 0 +0.1526078786915735 0.1030579368637691 0 +0.08641723656058847 0.1912697742276575 0 +0.01505667751073515 0.1850585152882425 0 +-0.02284223968495464 0.1965236674079066 0 +0.06749999999999996 0.1028841314754688 0 +-0.09506503545333256 0.1837925888321251 0 +-0.04911920773437737 0.121293480092494 0 +0.1568660398907627 0.1328269364883566 0 +0.08932118088675609 0.1962492796160424 0 +0.07680910046082061 0.1820955121775143 0 +-0.156506195082049 0.1165085592055524 0 +0.1451938275150033 0.1504333016048471 0 +-0.1074100820637436 0.1970225745456095 0 +0.02468205019991616 0.1929346777577456 0 +-0.05855262585150939 0.1609382393912354 0 +-0.09134109908048615 0.1510482263532581 0 +-0.0300325142997878 0.1477213245454455 0 +-0.05148828581232676 0.1359820216099254 0 +-0.08574792278277264 0.1151185114770198 0 +0.09750000000000009 0.1971492621557849 0 +-0.06367274064299899 0.1593567480510634 0 +0.01998591035897018 0.1395449947027424 0 +-0.04708555166642217 0.1723088644437022 0 +0.08355614992296494 0.1333677383203705 0 +-0.0509933487779852 0.1279948848772549 0 +0.0409915924830149 0.1585483754721908 0 +0.1027092640047618 0.1725311830851798 0 +0.1285943267725683 0.1161914322186453 0 +0.06631394417493108 0.1572791906552505 0 +0.1265089859854958 0.1819641505105738 0 +0.1161861415142864 0.1149500352960695 0 +-0.05885619225539859 0.1539932916603939 0 +-0.02715601255031334 0.1834743021120356 0 +0.1510828308605171 0.1363160286215019 0 +-0.01007994886367949 0.1528920356002389 0 +-0.0678832991222045 0.1528562446774675 0 +-0.06489391557929505 0.1659994864785128 0 +-0.1344632407745746 0.1558527287939498 0 +-0.09595579609517163 0.151434193903381 0 +-0.03198408224839326 0.1339354858559643 0 +-0.1316532085682373 0.1442767012890656 0 +-0.1410594609085564 0.1535103111770621 0 +0.1517598877736407 0.1295797867220518 0 +0.07367556944303483 0.1640797316799614 0 +-0.001262287550369451 0.1706371222369941 0 +0.009446819914932816 0.1343799789728856 0 +0.1106521719442193 0.1685423660038488 0 +0.006325885036646084 0.1418078884141939 0 +0.05721095969146976 0.1091312689096104 0 +-0.1287782392094761 0.1226416161720832 0 +0.06053522196653468 0.1175452341869132 0 +-0.08372353778599517 0.1285723497087304 0 +-0.0423623799798588 0.1507983894303196 0 +-0.02297183754592037 0.1766855640243594 0 +0.04738268063454457 0.1347172854096818 0 +0.1227661171941225 0.1693359486927433 0 +0.07533192222861326 0.1528590145594293 0 +0.1448163949597431 0.1845842015402614 0 +0.1284463274491797 0.1788682737254177 0 +0.003077658775132094 0.1360861194309468 0 +0.09779833528054882 0.184801200297005 0 +-0.0159501992711124 0.1484921853993421 0 +-0.1291599656194819 0.1186043381478394 0 +0.1150491585801995 0.1786363433543045 0 +-0.01757507617386416 0.1303685835367198 0 +-0.1246039362351959 0.1247535501664837 0 +-0.08167879726794604 0.1871743976851265 0 +-0.05887560420852665 0.1090004060054227 0 +0.09845091179064329 0.1034090683607008 0 +-0.1064355408415937 0.1834494057579088 0 +-0.1418870163072438 0.1783217633714642 0 +0.05277721125461268 0.191097204151942 0 +0.05917120912153132 0.147272477405251 0 +0.132322602052377 0.1454791092045411 0 +-0.01462790988041525 0.1150451706460808 0 +0.1006700121184531 0.1433591373750627 0 +0.02093673467558941 0.1686641289619215 0 +0.07509726322006376 0.1677213759077869 0 +-0.09509740463366563 0.1722209474611267 0 +0.1077509485574688 0.1906490568396727 0 +0.1074941023501928 0.102969658063208 0 +0.09260467101697469 0.1191044974115891 0 +0.003945505935413945 0.1087708939118182 0 +0.06410512708200709 0.1470464294333665 0 +-0.09637352528453105 0.1188151073698529 0 +-0.007125809300973516 0.1913651529022821 0 +0.1421921356721454 0.109579783855441 0 +-0.1317214763738172 0.1581289135661477 0 +-0.03506696311529229 0.1680654412614532 0 +-0.03607870705458668 0.1640718895520931 0 +0.07370354044442566 0.1418671352867375 0 +0.1321467319568682 0.1851507381026897 0 +0.0322571758190913 0.1570355768765316 0 +-0.04357368129069161 0.1661214909918507 0 +-0.1172047974764205 0.1473245836905612 0 +-0.1141049877081752 0.1587733670090866 0 +-0.02189540020149069 0.1674264736381162 0 +-0.08025595623243444 0.1354618237041185 0 +0.08249999999999995 0.1972869616143739 0 +-0.0153690347587593 0.1412437727415329 0 +-0.1395118197421805 0.1463816936594075 0 +-0.157126273703011 0.1523112969769648 0 +-0.03846263845163535 0.1077683779130824 0 +-0.05091646152952196 0.19034008377115 0 +0.03993284235341199 0.1209575147015316 0 +-0.1470498446253614 0.1787254273187933 0 +0.1572344852694708 0.1526675136692403 0 +-0.1567399593854329 0.1232904344788236 0 +0.03285534688168824 0.1209138436228629 0 +0.150851849361366 0.1660522374312469 0 +-0.0912500536534764 0.196690227646454 0 +0.02116302019594824 0.1158390843000215 0 +-0.04520581834415459 0.1234047260622966 0 +-0.001161999842345435 0.1074468852283972 0 +-0.1568266335415529 0.1924922268526942 0 +0.05382709541332412 0.196238911721939 0 +0.02607380531971978 0.1725423429409338 0 +-0.1180922775060995 0.1211860660044831 0 +0.120257052627469 0.1312816015801559 0 +0.07524141108747925 0.1748760002237152 0 +-0.0784187282730843 0.1126408402123763 0 +-0.03470435521584113 0.1104389859002825 0 +0.1088307253565146 0.1584532248364057 0 +0.04235249119172513 0.1625923798696734 0 +-0.1240065588900583 0.1766901239165566 0 +0.03465573530825199 0.1770006196893399 0 +-0.1302990590911274 0.1516475772498164 0 +0.1327904750347007 0.1029167345380803 0 +-0.1345266957825223 0.1926220691600483 0 +-0.0863474187563677 0.1924887246614957 0 +-0.1248300786681188 0.1845923477414728 0 +0.008115763485595262 0.1853421216096224 0 +-0.07103336044959155 0.1484704622101098 0 +-0.03855017142792727 0.1839929626661664 0 +-0.03474358873851289 0.1213212515939477 0 +0.05246451463019182 0.1457477108246916 0 +-0.09541115801569447 0.1569331598144091 0 +-0.1568638593388104 0.1081319108099248 0 +0.06172943838273469 0.1130927849396747 0 +0.1516886336493534 0.1489447795098268 0 +-0.1171880671348905 0.1773414669855988 0 +0.08744793110535512 0.1087081835349646 0 +0.1470625567560823 0.1567847434876169 0 +0.06708949602112126 0.1354989066584084 0 +0.09608188217390375 0.1586020399849734 0 +0.01070197797347413 0.1786903299459325 0 +-0.1570168428085205 0.1726158443748621 0 +0.06859147921936107 0.1686935576309246 0 +-0.1075190830898701 0.1797068432671533 0 +0.06271303789098456 0.170372392421149 0 +-0.1320306618346803 0.1619585039027147 0 +-0.07736002761373152 0.1477809426482795 0 +0.01756682633680155 0.1920179224642662 0 +-0.03668589131419257 0.1906390585149461 0 +-0.1315060972538992 0.1333346193325548 0 +0.006652354988804119 0.1465354034208702 0 +0.09668203849345861 0.171332290692261 0 +0.05711944923322272 0.1508378954033472 0 +0.05541430685928037 0.1035299547293211 0 +-0.06689455599867312 0.1347710841138774 0 +0.01754198709746849 0.1424313859694598 0 +-0.1101522749893637 0.1911779735452291 0 +-0.1068741293336718 0.1897989867094968 0 +-0.1191454779445156 0.1635483243142159 0 +0.04968871272143018 0.1147069726116263 0 +0.0521161449495102 0.1767959177434414 0 +-0.1241591306859823 0.1086281946344855 0 +-0.04740892238715733 0.1028834375044105 0 +-0.1526277400510151 0.1414194588942851 0 +0.1336798568156425 0.155745783540604 0 +0.06130610791014984 0.1301720560961936 0 +-0.1335480015048202 0.1080998921575421 0 +0.05364674368322625 0.1638025602504506 0 +0.03412289930072472 0.1102537462324486 0 +0.002802256532682203 0.1864156294318171 0 +-0.04664066822349639 0.1480084940107307 0 +0.1262362384610612 0.1714596667831391 0 +-0.02775958387682368 0.1652960557302039 0 +0.02462863641835598 0.1090082125622863 0 +0.1313817521119002 0.1619634921067054 0 +0.1209466345796717 0.1783102035085438 0 +-0.07257685142917612 0.1439785787274575 0 +0.06217059859980816 0.1245181113173944 0 +-0.1352410967771568 0.1810492576606542 0 +-0.07450283030816207 0.1500474776102598 0 +-0.008045419619775269 0.1176042912280177 0 +-0.01442368592226094 0.1589919377888352 0 +0.01781514605360753 0.1199410895365834 0 +-0.1222231054225594 0.1028339453779156 0 +0.03891316154370383 0.1780390349056279 0 +0.1340893787123489 0.1353838963025682 0 +-0.1447759430581901 0.1844415364900089 0 +-0.1173612415149296 0.1300172274895282 0 +-0.1206465909569125 0.1273760889234166 0 +0.1220109089191288 0.1912826593038648 0 +0.01874724997442499 0.150263838439175 0 +0.07430121286510379 0.1462100298448683 0 +0.07499793917787455 0.13287638857261 0 +0.04012643255483733 0.1874289994459616 0 +-0.05822604339714781 0.1681328893471761 0 +-0.004174798989683631 0.1180274380792919 0 +0.0917727828402413 0.1105735775744749 0 +-0.03965128787811359 0.1470165628574382 0 +0.1006679623570485 0.1919494126026157 0 +-0.07476345355052072 0.1185056269122487 0 +0.1274048413808676 0.1522514402942577 0 +0.157465744027534 0.1625 0 +0.105014227013167 0.1563758456073633 0 +0.1445550258438764 0.1339035478251467 0 +-0.0256353468073869 0.1928742083015186 0 +-0.05106625541860938 0.177778098450771 0 +-0.08809013977786305 0.1068988522591761 0 +-0.04181689821540015 0.1204042823293281 0 +-0.04116956903623288 0.174824902357276 0 +0.1122263623050133 0.1859971844356288 0 +0.01469710860087523 0.1659857727051379 0 +-0.02061278220203177 0.1566981694475147 0 +-0.01872421954964869 0.1606381383644816 0 +-0.08998895402635004 0.1895069752190501 0 +0.07382541631341895 0.1791438200036669 0 +0.1482935614085083 0.1726930743895648 0 +0.134683432253025 0.1684253215767361 0 +-0.05222796785423955 0.1563891160247321 0 +-0.06115285327241468 0.1401309110864816 0 +-0.07088331346655387 0.1084695183215705 0 +0.1210667377936612 0.1181378465894005 0 +-0.09967484934105511 0.1347293412565708 0 +-0.01401639464040365 0.1078330617230129 0 +-0.077669610918012 0.1972510313664378 0 +-0.1805462952434243 0.07297238383895988 0 +-0.1803760572527534 0.007136580510927366 0 +-0.1802511162229795 -0.02261422463605282 0 +-0.1797221172339322 -0.05728881283596953 0 +-0.1801057150981444 0.04782654797101948 0 +-0.1798901412354771 -0.07742283347519981 0 +-0.1800479770647588 0.02733506250898866 0 +-0.1826112390404693 -0.04021494771376156 0 +-0.1847040430732572 -0.007608471726514333 0 +-0.1856730769230769 0.08567307692307703 0 +-0.1861608240386472 0.0597321031969538 0 +-0.173046875 0.06137499999999974 0 +-0.1728880716695238 0.08337091467123822 0 +-0.1737010311919838 -0.01321329994859379 0 +-0.1872177952987014 -0.06841727421110914 0 +-0.1724435499663875 -0.06732329422974445 0 +-0.172457669824845 0.01731596275534534 0 +-0.1731245312909743 0.03674120447930124 0 +-0.18716061506779 -0.08656557329632023 0 +-0.172562330170358 -0.08720770187936158 0 +-0.1870308105056826 0.01874676029983992 0 +-0.1870826662902222 0.03629066494692532 0 +-0.1724183979272179 -0.03181463012941779 0 +-0.1729239312539205 -0.04724901880852535 0 +-0.1715992664689069 -0.0005147105837522561 0 +-0.1886453581146914 -0.03020615073864815 0 +-0.1884926740599295 -0.04973046415981214 0 +-0.1892255623640813 -0.01632845173649979 0 +-0.1897800664805895 0.001939518706147279 0 +-0.1703225064292685 0.0513300514341492 0 +-0.189702544321638 0.07612964542689718 0 +-0.1709124931951103 0.02745816474762479 0 +-0.1899998296700871 0.05073758520101041 0 +-0.1900644146892922 -0.0775106180511934 0 +-0.1698442322530864 -0.07750000000000007 0 +-0.1697897714572072 0.07265723480133476 0 +-0.1717162172042708 -0.05755750895077907 0 +-0.1711503658598585 -0.02261423899222576 0 +-0.1901365843365715 0.02749999999999989 0 +-0.1682731424222991 0.008835786288263797 0 +-0.1917713173847438 -0.05895459424175313 0 +-0.177708127129418 0.09092599542962515 0 +-0.1916613856499396 0.06720897566033285 0 +-0.1920408935423876 -0.040726318673213 0 +-0.1689259108941727 0.09070033466108621 0 +-0.1805334676453553 -0.09201795124750901 0 +-0.1921270061585313 0.09192563666233568 0 +-0.1680031915420624 -0.04005191035301203 0 +-0.1923476567063029 0.01010145586431958 0 +-0.1784590861835442 0.05580005259317811 0 +-0.1803890802958837 -0.0004935449563430787 0 +-0.180844340936373 -0.03065904741465288 0 +-0.1804961068864254 -0.04797563362350496 0 +-0.1803467470298633 -0.01442033894652115 0 +-0.1922023626495931 -0.007505199507227188 0 +-0.1800137129170438 0.01542530867810972 0 +-0.1800723294821186 0.03927826286679514 0 +-0.1800000000000001 -0.06541250972820885 0 +-0.1678019642745956 0.04385877999729446 0 +-0.1800426656081298 0.08028973917942983 0 +-0.180245751004052 0.06434879639697531 0 +-0.1927864280261924 0.04253247258273922 0 +-0.1927638616424027 0.08297809016780769 0 +-0.1671977621808658 -0.006684046659983914 0 +-0.1930230293810376 -0.02406245888173637 0 +-0.1930176277799332 -0.09175069412710654 0 +-0.1669823722200666 -0.09175069412710657 0 +-0.1929256844256133 0.05716293871498716 0 +-0.1676896611772243 0.06499990006386992 0 +-0.1668101045645869 0.05801477900887689 0 +-0.1675353424447582 0.0788099066051407 0 +-0.1755606473692392 -0.03878206520556842 0 +-0.1786197089750673 -0.08467095313562714 0 +-0.1669057448635885 -0.01614617080404003 0 +-0.1846934172239189 0.09312152999644921 0 +-0.1772648285098444 -0.007357536737656408 0 +-0.1932220130257402 -0.08375801433988121 0 +-0.166590755630745 -0.08357349234705128 0 +-0.1667094751426042 -0.06405463747586702 0 +-0.1667959701899103 0.02139247455064026 0 +-0.1668787813744788 0.033701650831123 0 +-0.1932920831376624 -0.07140602170654763 0 +-0.1667079168623374 -0.07140602170654797 0 +-0.1933809725198191 0.02156251273561954 0 +-0.1931796935093917 0.03387726750025553 0 +-0.166713452779829 -0.05123301217262902 0 +-0.1667134527798289 -0.028766987827371 0 +-0.1860997581634493 0.04395473747627945 0 +-0.1935727677754889 -0.03426599641273943 0 +-0.1744700659797144 0.04377296714164047 0 +-0.1744108310992441 -0.01805360659349437 0 +-0.1777163126561916 -0.07190677101645901 0 +-0.1670543863384736 0.0139655478437156 0 +-0.185157655733756 0.01093607176454357 0 +-0.1777881031902713 0.02158912595879358 0 +-0.1776105985940495 0.03503992516532811 0 +-0.1934799872428677 -0.06471099013613009 0 +-0.1853011211604703 -0.08294986453514681 0 +-0.1853247487112207 -0.0724155707798297 0 +-0.1742449796373449 0.06774358393701632 0 +-0.185379109990058 0.03257746282261975 0 +-0.18536873883315 0.02243002222673329 0 +-0.1665519123443307 0.002783920736969923 0 +-0.1749261642352415 0.07826109571627266 0 +-0.1745765157541606 -0.0270343262201029 0 +-0.1752043936765553 -0.05371850151457502 0 +-0.1750085413958118 -0.06227239539394981 0 +-0.1853487159441742 -0.02414485630824153 0 +-0.1941178420068203 -0.05395619041715074 0 +-0.1839956713739262 0.06884179321197109 0 +-0.1755434606418847 0.01263874335313174 0 +-0.1841693667703831 -0.06186988194073799 0 +-0.1746570105061798 -0.09316425691661992 0 +-0.1856972492221948 -0.09393588485790144 0 +-0.166311310473767 0.0853992017932395 0 +-0.1948687120620465 -0.04651635453330612 0 +-0.1745006572268559 0.005009240651982206 0 +-0.1871329445924933 -0.03611411744847016 0 +-0.1857468148520688 -0.05449439321952101 0 +-0.194785649354844 -0.002834893177486657 0 +-0.1944399022195124 -0.0130855876064052 0 +-0.1839435754408222 0.05211546270564994 0 +-0.1944606049307071 0.07217034822396191 0 +-0.1659994692684664 -0.03491566943745236 0 +-0.1659677035193972 -0.04501240739846096 0 +-0.1941270458779073 0.0152569516847245 0 +-0.1848666786080183 -0.04529870699036789 0 +-0.17350568715947 -0.08197311983335452 0 +-0.1946466790590633 0.06201637361183188 0 +-0.1735394768544069 0.09444104856621868 0 +-0.1941363479818309 0.005265610245226392 0 +-0.1838260600875473 0.003575537203466864 0 +-0.1886262344172824 -0.0114237317058119 0 +-0.1885684319687272 -0.003756673107612134 0 +-0.1934750112522695 -0.02970350402138072 0 +-0.1859520927847755 0.08003910907146816 0 +-0.1840174413289215 -0.01862514162843762 0 +-0.1756134811358978 0.05096957667056885 0 +-0.1804262821331602 0.08553126319323802 0 +-0.1653550573849166 0.04762743674894229 0 +-0.1652593229207878 0.03858081761864809 0 +-0.1949027407952323 0.07792788539370568 0 +-0.1944992509961998 -0.01891714927058436 0 +-0.1765914167022765 -0.04411993060416368 0 +-0.1949785202045994 0.05211551205730124 0 +-0.1732969631872552 0.05597181517162165 0 +-0.1720872278631609 -0.0723967774115816 0 +-0.1954684602094286 0.08727907497647423 0 +-0.1723235829339413 -0.005693304281161913 0 +-0.1721198935595303 0.03212567886948811 0 +-0.171907952901057 0.02194397850427173 0 +-0.1733035783478762 0.08874904178909504 0 +-0.1634203082569579 0.02749999999999993 0 +-0.1955927909391829 0.03792132786302675 0 +-0.1642590131159551 -0.002324923298611699 0 +-0.1965939314095998 -0.07750489929959969 0 +-0.1648336465877668 -0.07815856332473467 0 +-0.1634051191591389 -0.05751265034716303 0 +-0.1650234324102915 0.07234100474410381 0 +-0.1634266411075964 -0.02246815027536925 0 +-0.1849753562853015 0.07474360767350807 0 +-0.196606384522042 0.02752000611885143 0 +-0.1642066458204205 -0.01189252007509951 0 +-0.1652340876731759 0.09471595264199159 0 +-0.1750452261525547 0.02672790103587265 0 +-0.1881533257334625 0.05531513961999619 0 +-0.1795308626312958 -0.03573180027849272 0 +-0.1640560858882034 -0.08743006025888712 0 +-0.195709029563312 -0.08771215842878827 0 +-0.187954441390857 0.007172972491183883 0 +-0.1750672744594042 -0.0769858872910312 0 +-0.163519026980931 0.006799302667243918 0 +-0.196024097122101 -0.05788301105488809 0 +-0.1822627278992167 -0.08684083751828225 0 +-0.1948658233224972 0.04702985713993504 0 +-0.1812692836966503 -0.05284054299226312 0 +-0.195929463421273 0.09590133819795396 0 +-0.181335295828936 0.06003869638361613 0 +-0.1804901306690646 0.0951866201126183 0 +-0.1817240189343184 -0.06925992462591553 0 +-0.1825544318340032 0.01948239339027792 0 +-0.1825860537420086 0.03579208593569763 0 +-0.164300469515851 0.06221876854954606 0 +-0.195552327182502 -0.04259176257774212 0 +-0.1902829085844094 0.08671893653009397 0 +-0.1888126811727646 0.07101218318336132 0 +-0.1650008423359193 0.05350043744105706 0 +-0.1747023208219062 0.0726326133580259 0 +-0.1893265855930514 0.06294278906092243 0 +-0.1640030623753122 -0.06752613902284424 0 +-0.1878278767350226 0.09546121228128984 0 +-0.1961150855324117 0.06734224249944669 0 +-0.1713039508763981 -0.04288135931855803 0 +-0.1845132078004719 -0.03263837916981459 0 +-0.1840997694259455 -0.003301779616507211 0 +-0.1785432865026421 -0.09632448021179266 0 +-0.1821718093240937 -0.0265125479522207 0 +-0.1885068572250093 -0.06369709429086684 0 +-0.1645314565842768 0.08958690589531934 0 +-0.1715407460044236 0.04660360769523143 0 +-0.1708834282235251 0.01328930178574309 0 +-0.1763220116424572 -0.003062840457387086 0 +-0.1846516532301733 -0.01308167955437228 0 +-0.1846344816263367 0.06391026488765597 0 +-0.1636700906596267 -0.0385382239147562 0 +-0.1769159493182283 -0.08839201469680948 0 +-0.1712852133594872 -0.03631460707663771 0 +-0.1964423557946998 0.01159949846545698 0 +-0.1763077560625892 -0.04940485984959002 0 +-0.1808390776032623 -0.009966651314240762 0 +-0.1784258731621862 0.00359215517089503 0 +-0.1641457941559306 0.01749868441889102 0 +-0.177228231336401 -0.01152041123655156 0 +-0.1894013181236671 -0.07306437305561911 0 +-0.1832991473672665 0.05610621690210026 0 +-0.169392851988558 0.09570712114668072 0 +-0.1821179874419348 -0.09645124315812456 0 +-0.1829969959220235 0.08907657067045614 0 +-0.1769706267844586 0.05968683312158656 0 +-0.1712415375009447 -0.05176601040061013 0 +-0.1701139573084189 -0.02783850194349083 0 +-0.1960237806660443 -0.06787955328236128 0 +-0.1689351709901364 0.06164305891139932 0 +-0.1860376213009774 0.04836316899955343 0 +-0.170629706550682 -0.01828039425163444 0 +-0.1894310118490271 -0.08221568748115221 0 +-0.1644410836026633 0.08141294821428494 0 +-0.1955196625039289 -0.03754399073132327 0 +-0.1700185008258255 -0.09583801869728692 0 +-0.1899999425169678 -0.09587819091413843 0 +-0.1894489797969001 0.03210902510325616 0 +-0.1894670035967674 0.02321018440100797 0 +-0.1818139028451383 0.04358617869647835 0 +-0.1844371641386738 0.04005723615991678 0 +-0.1636644081793842 0.04281204928996349 0 +-0.1704453577606969 -0.0632439025146517 0 +-0.1764462572387605 -0.03264482527647924 0 +-0.1709464925354657 0.003953149881256311 0 +-0.1888581874583546 0.01364216753810359 0 +-0.164355854795291 0.067499719987324 0 +-0.1892200988767505 -0.02137911956095903 0 +-0.1957853542161679 -0.09578190788292851 0 +-0.1642177196742976 -0.09577521251345329 0 +-0.1897965177579111 -0.05403151581019281 0 +-0.1761828548438831 -0.02260291670606544 0 +-0.1783535068931242 0.06863232421874968 0 +-0.1968110017997334 -0.02285919351508478 0 +-0.1841743116206185 -0.05006794819709383 0 +-0.1758324004132248 0.03981265814429792 0 +-0.1788872798421605 -0.01850826694117172 0 +-0.1963893304605385 -0.007632240041588432 0 +-0.1966513288053607 0.04250000000000001 0 +-0.175830356610159 -0.05755905015782529 0 +-0.1785337078882007 0.07640301754181501 0 +-0.1852612973194289 0.02752021963282571 0 +-0.1683568293309531 -0.06756292879562631 0 +-0.1852015690374985 -0.07760573185212129 0 +-0.1807346450805024 -0.04382906339531854 0 +-0.1640019756111093 0.07699084905003707 0 +-0.1897929557987182 0.04567655140614039 0 +-0.1770169528018907 0.08311112404973661 0 +-0.1709489023132606 0.04089158132229396 0 +-0.1631326842234483 -0.007180298006739045 0 +-0.1809527255810249 0.01123018402501061 0 +-0.1764973308104055 -0.06794504036577693 0 +-0.1711246145312849 0.07972213199114597 0 +-0.1762427508447617 0.01760008645361699 0 +-0.1794841862614308 -0.06071862671223976 0 +-0.1903683177496442 -0.04516672626203543 0 +-0.1889674336246859 0.0829817200246486 0 +-0.1886096086747191 0.04091651645308274 0 +-0.1967745380793816 0.08250000000000002 0 +-0.1818946475969769 0.02363363290124743 0 +-0.1813178994809017 0.03139116949788016 0 +-0.1963528394050751 -0.06181967343467277 0 +-0.1799939077356486 0.0519387779831138 0 +-0.1873039239563841 -0.04019685269193391 0 +-0.169993837401701 0.0686309340696124 0 +-0.1872668802578304 0.0903294938439503 0 +-0.1636985581399283 0.0116761089782299 0 +-0.1773136449942039 -0.08093028674943302 0 +-0.1966276224094929 -0.03289200987816165 0 +-0.1634360948654167 -0.04195411950461474 0 +-0.1758872798539559 0.06422392170540157 0 +-0.1692607851555819 -0.01064253273075503 0 +-0.1816925706993108 -0.07372481065674244 0 +-0.1706879892533877 -0.09118631895087168 0 +-0.1887331945453715 -0.09090737364729967 0 +-0.1631330556274218 -0.01750000000000004 0 +-0.1840945873383109 0.01491048094931422 0 +-0.1963689692528054 0.001666703016495733 0 +-0.1967959748203024 0.05743725657976472 0 +-0.1701834816996846 0.08627801091496656 0 +-0.1885126212878494 -0.007579438526173784 0 +-0.163764962423128 -0.0312486845357783 0 +-0.1637649624231278 -0.04875131546422173 0 +-0.1843236076456825 -0.06573133695936767 0 +-0.1894813064776306 -0.02643998118902687 0 +-0.1812041943705985 -0.08153548601499339 0 +-0.1962626760221375 0.01881285519010453 0 +-0.1839100598692228 0.007695879417160324 0 +-0.1968319471843583 -0.08245705916061065 0 +-0.1630102097627535 -0.08249999999999993 0 +-0.1631478828512891 -0.06246195502890699 0 +-0.1768287665820937 0.09654818168487618 0 +-0.1686335568524129 0.01781489525575805 0 +-0.1683863074088 -0.002486612817307972 0 +-0.1829699488901614 0.08261376303543744 0 +-0.1964631190237467 0.09158817921947415 0 +-0.1967703011049811 -0.09205760228236054 0 +-0.1631238668260506 -0.09201158448744279 0 +-0.1968468372837983 0.03247175420782274 0 +-0.1684390798285813 -0.08707607456929969 0 +-0.191212248638529 -0.08715158355342469 0 +-0.1759957423094141 0.04664802526724544 0 +-0.1968729869759968 -0.07257742916692549 0 +-0.1633944145464573 -0.07267729260982855 0 +-0.180603135091775 -0.00529847080144148 0 +-0.1631924237029465 0.03249000853110078 0 +-0.1629760711831037 0.02249999999999996 0 +-0.1629662034538876 0.0575 0 +-0.1963146104042376 -0.05005460034710728 0 +-0.1965144595350399 0.02297750495634632 0 +-0.1913203036156587 -0.06819588444710567 0 +-0.1635179361172276 -0.05291785338438315 0 +-0.1635215231086372 -0.02707894671937228 0 +-0.1716329673433937 0.06476939978121654 0 +-0.1836530184782043 -0.03654105743166632 0 +-0.1858208291307528 -1.015298545774466e-05 0 +-0.1911166945394347 0.03727454574154762 0 +-0.1752326600378409 0.001314079028896576 0 +-0.1696662862918064 0.03640818662417088 0 +-0.1696354668059523 -0.08163963344992221 0 +-0.1908202071619784 0.07975285181314402 0 +-0.1687473174036136 0.08249885236500264 0 +-0.1965852720965667 0.008393312915000593 0 +-0.1693097476842145 0.05534544392480188 0 +-0.1876861610832037 0.06678320120084873 0 +-0.1686009291881781 -0.04818902918588737 0 +-0.168600929188178 -0.03181097081411249 0 +-0.191482359684761 0.01841815734763689 0 +-0.1674057692219741 0.07537113153624179 0 +-0.1787750598930316 -0.04063839255827238 0 +-0.1850481831281591 -0.02880783308212428 0 +-0.1785466349042427 -0.02739580463354392 0 +-0.1902426197699675 0.0594338688409383 0 +-0.1671199278535076 -0.02019656865157644 0 +-0.1915143400084406 0.05383279389832374 0 +-0.1965327286214297 -0.0263163594231032 0 +-0.1762686024163738 0.08633766782658661 0 +-0.1909036709570966 -0.03708797300789252 0 +-0.1780483593546258 0.04348744001457946 0 +-0.189851833371897 -0.03368056208967536 0 +-0.1702797722852386 0.05847001940333989 0 +-0.1923264456734315 -0.04990930858826742 0 +-0.1765708366186005 0.008059755050546442 0 +-0.1848774508759857 -0.09005352411346253 0 +-0.1930452597635894 -0.07982439242788494 0 +-0.1837372504421709 0.09664518242752496 0 +-0.1671080224098783 -0.05997346610660881 0 +-0.1754532749727949 -0.08493005665900011 0 +-0.1740664178919938 -0.009458021696059308 0 +-0.193175867265824 0.02974128477061469 0 +-0.1930289798348988 0.02519869981097056 0 +-0.1673014589461324 0.02971471179844102 0 +-0.1672190424453786 0.02508488826682961 0 +-0.1929980571166135 -0.07515769889825845 0 +-0.1672244518070198 -0.07499423703745683 0 +-0.1709139971187287 0.07624235233469362 0 +-0.1871404048268731 -0.05855614108124884 0 +-0.1672837141952149 -0.0551600835603622 0 +-0.1670076446696413 -0.02482723240156759 0 +-0.1835538239678216 -0.0581388026522717 0 +-0.1920991295362452 0.09694535212054339 0 +-0.162662248663851 0.002487416706872221 0 +-0.177228318970359 0.03052394741551154 0 +-0.1707561948147379 -0.01511285568056484 0 +-0.1768950591327892 -0.01520779972274368 0 +-0.1825439636336686 0.07792693980980708 0 +-0.1727863362781052 0.008630996168487264 0 +-0.1626139128516063 0.09712337933881215 0 +-0.1965802967419993 -0.01591814856923028 0 +-0.162503868078389 0.09249999999999997 0 +0.1800439403845455 0.07251606643225135 0 +0.1799307605034233 0.02254340739857064 0 +0.1797229700551697 -0.0175076163399807 0 +0.1795055864927848 -0.06693491014449811 0 +0.1798924480924413 -0.04155957497364753 0 +0.179850359106162 0.04710245553799886 0 +0.1810199735477013 0.003160370426434314 0 +0.1760680863866934 -0.08377408953958648 0 +0.1741029078046125 0.08483519828137141 0 +0.1861300687806886 -0.03013634720846584 0 +0.1859747145351025 0.03403874144207943 0 +0.1863446474115505 0.06008928354465222 0 +0.1738320931996696 -0.0551472543833701 0 +0.186953125 -0.05362500000000011 0 +0.1723613537993106 0.06117345802679958 0 +0.173046875 -0.02862500000000018 0 +0.173046875 0.03362499999999995 0 +0.1868830143987363 0.08359190311793324 0 +0.1871072967067017 -0.07776420907467887 0 +0.1723813319970844 0.01243986880466477 0 +0.1723813319970844 -0.007439868804664714 0 +0.1870826662902221 -0.006290664946925277 0 +0.1876785167727718 0.01255937806072488 0 +0.1870134765683544 -0.08963390314834191 0 +0.1718274394358345 -0.07389921000655431 0 +0.1703225064292687 -0.038669948565851 0 +0.1703670306115119 0.04385884332505169 0 +0.1896774935707314 -0.06366994856585088 0 +0.170795585194236 0.07603545637735905 0 +0.1713956212123488 0.003244660711707151 0 +0.1896297522679475 -0.02046495899677948 0 +0.189785643718802 0.04453514975041583 0 +0.1889479551537387 0.06970935329406573 0 +0.189785643718802 0.0254648502495839 0 +0.1902900530912297 -0.03839262767087227 0 +0.1698505646068768 0.02231691632553608 0 +0.1702754829925091 -0.01731238851564859 0 +0.188985536822682 0.002500747173359229 0 +0.1690566399212112 -0.06431631450883887 0 +0.1696134428223844 -0.0903865571776156 0 +0.1683615098491716 0.05268364800410631 0 +0.1825609892818734 0.09154138696043986 0 +0.1683744738440307 -0.04766239969093823 0 +0.1906164257756429 0.09152688962950672 0 +0.1920265472083871 0.05318675583094402 0 +0.179595499020714 -0.09228874432124951 0 +0.1678823065899688 0.09191706423545742 0 +0.1681390751723439 -0.08210896568329276 0 +0.1794403120677195 -0.07581614897536398 0 +0.1681108114675479 0.06808869069366386 0 +0.1785396952084738 0.03921423827970495 0 +0.1791026879404076 -0.03449019689043956 0 +0.1790447908360863 0.05570101602990814 0 +0.1815018613194835 -0.05927032608058103 0 +0.1923413637234049 -0.04777722828651364 0 +0.1922595383305323 0.07718944737396942 0 +0.1800461358528126 0.01042455554349928 0 +0.1800137129170439 -0.009574691321890252 0 +0.1923076158708455 -0.07131541232580976 0 +0.1799573343918699 0.08028973917942986 0 +0.18 -0.02523535156250021 0 +0.1799999999999999 0.06476464843749977 0 +0.1796366969553806 0.03111539898760616 0 +0.1797581923424839 -0.05059303868739369 0 +0.1927641449789906 -0.01252371629313438 0 +0.1926386424289638 0.01786462513637343 0 +0.1924669799642411 -0.08363589490686948 0 +0.1672718451290651 0.08302951631868963 0 +0.1929256844256134 -0.02716293871498738 0 +0.1929256844256135 0.03783706128501248 0 +0.1930643340135911 0.06234851421494399 0 +0.1669531249999999 -0.05734670096978388 0 +0.1676230098212065 -0.02490593342224558 0 +0.1676896611772243 0.03000009993612989 0 +0.192956515714271 -0.05688338487490829 0 +0.1668945731443951 -0.03207133484975837 0 +0.1669080152195312 0.03710583204338733 0 +0.1932203101446289 -0.0934910225305149 0 +0.1832833500914729 -0.0838276360336121 0 +0.1752994696829442 0.09305629432731566 0 +0.1667166363099224 -0.01106710769507785 0 +0.1667378990655684 0.01636646841394132 0 +0.1667091357153657 0.008867570345284376 0 +0.1667133109790525 -0.003567725804912474 0 +0.1931831150712872 0.008875563410115908 0 +0.1931796935093918 -0.003877267500255597 0 +0.1855251958870811 0.07642524878652365 0 +0.1857535711421069 0.01910022668078359 0 +0.185636195156835 -0.01376128204897328 0 +0.1856627203120133 -0.04631204442283942 0 +0.1847998143619659 0.05221519269776231 0 +0.1672965864543621 0.06052435767888481 0 +0.1934740487321608 -0.03417195004747248 0 +0.1937510973206086 0.03087019130250916 0 +0.1854980184595782 -0.07128527235351187 0 +0.1746375062225015 0.06880334042089378 0 +0.1937584845960291 0.0848653123472181 0 +0.1775958614151255 -0.003507962557008634 0 +0.1778772391334341 0.01766950043777734 0 +0.1738788516434405 -0.02185566264301047 0 +0.1742449796373448 0.02725641606298358 0 +0.1853760819850629 -0.001630440372781433 0 +0.1852352256855575 0.006583600465722387 0 +0.1758715441537983 -0.01277745426476264 0 +0.1750181986652152 0.007218327548510498 0 +0.1663985469959165 -0.06946749884830507 0 +0.1760566292353231 -0.04717054808571164 0 +0.1944295758000117 -0.07689883970245105 0 +0.1742414403399241 0.04817656468827591 0 +0.1758562681216388 -0.06328056983024941 0 +0.1653645540246223 0.04789654259291507 0 +0.1747908390515518 -0.06862092283590647 0 +0.1840959410741081 0.04302335965191338 0 +0.1847482437223498 -0.03562593200849282 0 +0.1655328038047834 -0.04266848338967233 0 +0.1649137677567489 -0.07740262732776435 0 +0.1744164441004784 -0.09390890447221298 0 +0.1849854870575875 -0.09378912809976149 0 +0.1944637105117584 0.04806962726254665 0 +0.1864605231455928 0.09444104856621839 0 +0.1654821441380506 0.072790673647293 0 +0.1949005543930182 -0.042914205501486 0 +0.1835644196287196 0.06834328285533944 0 +0.1833021780342402 -0.02196570659720676 0 +0.1856155041077373 0.02933252603083395 0 +0.1656174123342756 -0.09438258766572429 0 +0.1942540440677759 0.07202448578953963 0 +0.1951974739380961 0.05758284542024324 0 +0.1762357696714721 0.07655874582150632 0 +0.1646297556387334 -0.05244928763043155 0 +0.1730732060330759 -0.07978103458077093 0 +0.1652552909003039 -0.0868927121057559 0 +0.1863806929522576 -0.05894642638422164 0 +0.1735852370847774 0.03897637248364727 0 +0.1736082617457873 -0.03402389658070792 0 +0.1946597028354181 -0.06744767834490246 0 +0.1822720457634863 0.08534849430368259 0 +0.1954785539588159 -0.05248221096042145 0 +0.1949785202045994 -0.02211551205730159 0 +0.1947713812302018 0.02320462830071663 0 +0.1757475154060378 -0.03910364989717925 0 +0.1842419732145596 -0.06402724303112468 0 +0.1748981397858775 0.0563036164609672 0 +0.1650484790323748 0.04160438605705689 0 +0.1752763747046346 -0.08868082791022763 0 +0.1760443060482056 0.04366068362495107 0 +0.1951267444235801 0.04273809762127347 0 +0.1645772192114216 -0.06205825168138791 0 +0.1950149149682928 -0.08823043597330692 0 +0.1721896993035752 0.0175763357777142 0 +0.1645379711505668 0.08728519693704613 0 +0.1719316386097876 -0.003057839236228598 0 +0.1864207711344118 0.08878662764478192 0 +0.1634203082569578 0.002499999999999967 0 +0.1955905171588563 -0.007920434364087578 0 +0.1955780599151695 0.01295504709399564 0 +0.1650642338213436 -0.03653989303476089 0 +0.1648865333432837 0.02257286349782795 0 +0.1648049202728111 -0.01753445814443901 0 +0.1651425303214841 0.07844675749599785 0 +0.1826297628257328 0.01494464623672623 0 +0.1729230598726724 0.08051015637536466 0 +0.1966172086059406 0.002500000000000007 0 +0.1946152802993766 0.09460105855762752 0 +0.1875675130635727 0.06493548281966632 0 +0.1849306212223152 0.02338230227197813 0 +0.1880548706808406 -0.02553479060510406 0 +0.1846220547156894 -0.04149124785795767 0 +0.1882054789779647 0.03953016540083146 0 +0.1653585317845421 0.06440395166533092 0 +0.1746697175858206 0.0228967007615455 0 +0.1960050297986847 0.06637909292439481 0 +0.1717136325960766 -0.06007047532371295 0 +0.1947830321730919 -0.0169791520932897 0 +0.184968748570657 0.04779805941437885 0 +0.1634908503717767 0.05241254694994701 0 +0.1640720887034771 0.09589990946014089 0 +0.1772777509742139 -0.02988387166079877 0 +0.1786184963789557 -0.0549606269939823 0 +0.1813102230505964 0.03506326115902174 0 +0.1773489753507904 0.0605924180594859 0 +0.1795098693309348 0.09518662011261815 0 +0.1767303778778985 0.001720608342239651 0 +0.1796008282186436 -0.08648809743630252 0 +0.172074063411839 -0.04387154850144526 0 +0.1825733234505097 -0.005428326501853883 0 +0.1643030148335353 -0.02778008107113253 0 +0.1643144567522716 0.03279846160077726 0 +0.1700344767879801 -0.05218374797632097 0 +0.1696883116728221 0.08690735545100481 0 +0.1949419941070659 -0.06148149946052944 0 +0.1640141695741972 0.01248924770393432 0 +0.1639451442863589 -0.00744250806157391 0 +0.1718361980754168 -0.08526816921175269 0 +0.1905246291297916 0.05806770402104328 0 +0.1955597075888877 0.08087056122868182 0 +0.1718888464968023 0.09544049182541153 0 +0.1637959760728243 -0.04752635718042823 0 +0.1761893992332993 -0.07293473801809078 0 +0.18801127219854 -0.08230438866932413 0 +0.1776251349440911 0.08900338674789005 0 +0.1957329312432817 -0.03809575664396614 0 +0.1963375463316483 0.05276784570274679 0 +0.1951430570799075 0.08921916897892904 0 +0.1891873172553632 -0.09575333810987072 0 +0.1711127700696987 0.0713090036050649 0 +0.1834175790012189 -0.07909955245971347 0 +0.1888258079180461 -0.03365141361991726 0 +0.1884351353675619 -0.06847434414958053 0 +0.1771951058572431 0.05165787334105146 0 +0.1754825054506735 -0.0178939107565499 0 +0.1962319107410227 0.02733045527783551 0 +0.1752198465067487 -0.05131136367654236 0 +0.1782201009334312 -0.09638348995674326 0 +0.1636779634210526 -0.08238819439967478 0 +0.1893085303197124 -0.04412571085616021 0 +0.1699092451608126 -0.09555249722381139 0 +0.1890059756494018 0.07426681291488881 0 +0.1835640971975065 0.05576060468019271 0 +0.1892661694977592 0.04974400488533901 0 +0.1810921096399705 -0.03821666032076906 0 +0.168928946876825 0.06420602810297711 0 +0.1963746138333823 -0.07250000000000002 0 +0.1807784636388036 -0.07136506994642546 0 +0.1909982165739746 0.08203641717275549 0 +0.1905608939256682 0.03432781239933373 0 +0.1831859193551783 0.03888362782412629 0 +0.1906071480114419 0.09570712114668048 0 +0.1882649857859716 -0.04932809680717658 0 +0.1767720358526627 -0.05912155264631784 0 +0.1769978426266251 0.03501531794349626 0 +0.1818721874662362 -0.03067767225577731 0 +0.1830222561435712 -0.05528879597625955 0 +0.1787674983139701 -0.08060557929468282 0 +0.1965440944150478 -0.04763472894968421 0 +0.1689623108759635 0.03336530410154527 0 +0.1687480073510449 -0.02831022759383586 0 +0.1704096338327872 0.008245734629069572 0 +0.1637473983401405 -0.07297818169179852 0 +0.1834602664035614 -0.08859057181936542 0 +0.1898198970641098 -0.002719234349932686 0 +0.1701130943265596 -0.01183882419856095 0 +0.1638407576803026 0.06813346719236001 0 +0.1815670052957067 -0.01353266529656425 0 +0.1843068629032372 -0.01000485285892193 0 +0.1898962996882664 0.007922844927152587 0 +0.1957592675997527 0.03466414173692768 0 +0.1957592675997524 -0.03033585826307201 0 +0.1643412224345069 0.0274920774403253 0 +0.1642704485569585 -0.02245412752885815 0 +0.1842250615526211 -0.05039479310920597 0 +0.1893317062192573 -0.01567139841656626 0 +0.189466259594458 0.02107631062570058 0 +0.1817774401188972 0.06045584249491223 0 +0.1757744101625658 0.06497335935510454 0 +0.1779382955792385 0.02678835277141755 0 +0.1781487470613518 -0.02162225965729884 0 +0.1841537886608275 0.08039262268715272 0 +0.1966513288053607 -0.0125 0 +0.1966373471075023 0.01757935758699947 0 +0.1843475621019234 0.001830716197658069 0 +0.168209488164774 0.0124627229310268 0 +0.1683640209344607 -0.007440707395000214 0 +0.1963633457661528 -0.08243209667991269 0 +0.1798089175041896 -0.06293002296350118 0 +0.1908241492951997 -0.05277707662918538 0 +0.1889166748111962 -0.07431054459351073 0 +0.1816587062082672 0.07647538472247398 0 +0.1699091585000144 0.04889200561171831 0 +0.178105840100956 0.08398934989718769 0 +0.1809240756598011 -0.04576490801822875 0 +0.1766329018264494 0.01312198669146569 0 +0.176489291860296 -0.007464151087315539 0 +0.1790303592264984 0.006447398206706981 0 +0.1889682743091057 0.01644148703732494 0 +0.1884300425299335 -0.01087322511850283 0 +0.1841338268712143 0.01052130265315481 0 +0.1964146579974392 0.07701689887843818 0 +0.1960580313214839 -0.09605803132148413 0 +0.1632254619206183 0.08249999999999995 0 +0.1838718609924011 -0.02670997364581084 0 +0.1727478295318735 0.09019329847807514 0 +0.1811989878399177 -0.001043252336982162 0 +0.1783391275403673 0.06863122692373269 0 +0.171437359517523 -0.02511066869809041 0 +0.1697437133364896 0.02624032987110761 0 +0.1897208214603703 0.03026859636838198 0 +0.1897583215153481 -0.0868595973631285 0 +0.1845753681810584 0.07287427071817795 0 +0.1756315973660882 -0.02538880237028315 0 +0.1757515872377228 0.03078190203278223 0 +0.1640064812257099 -0.06616841300770637 0 +0.1639653398421288 -0.09070877054577582 0 +0.1639627762115392 0.05658763534260899 0 +0.1800497421318824 0.04299043364883698 0 +0.1818348320775886 0.01894372139112157 0 +0.1751941165138035 0.072308973263468 0 +0.1968533675500744 0.06226209051191642 0 +0.1910666049350751 -0.07962886042256698 0 +0.1704578199550462 -0.06908581779743468 0 +0.1902624743013498 -0.02995909308111769 0 +0.1840402002229098 -0.074890394785483 0 +0.1630288142280118 -0.05750000000000002 0 +0.1697730817317473 0.05678547727947122 0 +0.1897316284411392 0.08627004329091081 0 +0.1845912581313954 -0.01724170178163844 0 +0.1829340104249337 0.09638778854353885 0 +0.1633991226707553 -0.01258652014296566 0 +0.1634137401124183 0.01761921620713336 0 +0.1635377814465387 0.09158797726174192 0 +0.1968468162258095 0.00747227521564838 0 +0.1968472082361607 -0.002470847484157651 0 +0.1631310430713649 0.007449849465409739 0 +0.1629760711831035 -0.002500000000000044 0 +0.1968509476736216 -0.05733133625467952 0 +0.1630406934856367 -0.03244227972488818 0 +0.1630411687670249 0.03744839023850589 0 +0.1687150121340747 -0.02152887315871537 0 +0.1878798032199388 0.05455800152689048 0 +0.1691171120880848 -0.07780684310305894 0 +0.183850804044548 0.06371770803041399 0 +0.1969215973670966 -0.09230841716992812 0 +0.1715731878774575 0.03021150866742475 0 +0.1695199310613524 -0.03469913271242103 0 +0.1904271437072571 -0.05968584933002199 0 +0.1695218888988422 0.03972365933263163 0 +0.1820665065037885 0.02716485463710788 0 +0.1913898726922163 0.01238661376441361 0 +0.1912342610292911 -0.007258855871955768 0 +0.1836918354346576 -0.06841736792502813 0 +0.1693122015804696 0.08005815565834462 0 +0.1816759339269448 -0.0965683906046482 0 +0.1723179533395299 -0.04859785853011377 0 +0.1881376215834256 0.07898374200887054 0 +0.1767425112202162 -0.04330520677970046 0 +0.1925283095634115 -0.09714177843586842 0 +0.1967326944459931 -0.02692286180707219 0 +0.196648811935516 0.03831028016522287 0 +0.1758595710167799 -0.07660734217509257 0 +0.1916214520060669 0.06623617555398684 0 +0.1915108878864901 0.04116011851438331 0 +0.1914606131405347 -0.02378264525258916 0 +0.1895287915284164 0.06180860539678323 0 +0.1813834170177557 0.05115366914967266 0 +0.1676525368151263 -0.07332024479213468 0 +0.1726215969496925 0.05238577569088761 0 +0.1680751541821773 -0.0609479356209309 0 +0.1706333318959315 -0.05618704466329697 0 +0.1898128670387098 -0.09155941950203959 0 +0.186294375776259 -0.08588699204520528 0 +0.1761221604780681 0.09653196362487167 0 +0.1672240823412697 0.01997340298018501 0 +0.1671082030364424 -0.01432658637958032 0 +0.1707566671339564 0.08335020525773357 0 +0.1930477113974209 0.0001606236909184138 0 +0.1929690662324621 0.004966567825052575 0 +0.1718209664330749 0.06642564670075062 0 +0.1671693326821554 0.005021006834152783 0 +0.1672677138205676 0.0002733504174531309 0 +0.1703635296605159 -0.03154591834734467 0 +0.1704048654158228 0.03655923359224229 0 +0.1627691871180678 -0.09723081288193215 0 +0.1679282281941604 0.09704660306797701 0 +0.1688470033333692 -0.08687754037902287 0 +0.1778160721041099 -0.06996391023623019 0 +0.1831528097815965 0.03193017084205892 0 +0.1633235788900887 0.06130318893736495 0 +0.176356743376839 0.08039172065138248 0 +0.1895083253337971 -0.05638354744366748 0 +0.192852170894201 0.02742774429980543 0 +0.1726246792001396 -0.06510777955718611 0 +0.1972795804471646 0.09227087902724006 0 +0.197366970972743 0.09710546935041524 0 + +CELLS 15576 61816 +2 1 14 +2 14 15 +2 15 16 +2 16 17 +2 17 18 +2 18 19 +2 19 20 +2 20 21 +2 21 22 +2 22 23 +2 23 24 +2 24 25 +2 25 26 +2 26 27 +2 27 28 +2 28 29 +2 29 30 +2 30 31 +2 31 32 +2 32 0 +2 2 33 +2 33 34 +2 34 35 +2 35 36 +2 36 37 +2 37 38 +2 38 39 +2 39 40 +2 40 41 +2 41 42 +2 42 43 +2 43 44 +2 44 45 +2 45 46 +2 46 47 +2 47 48 +2 48 49 +2 49 50 +2 50 51 +2 51 52 +2 52 53 +2 53 54 +2 54 55 +2 55 56 +2 56 57 +2 57 58 +2 58 59 +2 59 60 +2 60 61 +2 61 62 +2 62 63 +2 63 64 +2 64 65 +2 65 66 +2 66 67 +2 67 68 +2 68 69 +2 69 70 +2 70 71 +2 71 72 +2 72 73 +2 73 74 +2 74 75 +2 75 76 +2 76 77 +2 77 78 +2 78 79 +2 79 80 +2 80 81 +2 81 82 +2 82 83 +2 83 84 +2 84 85 +2 85 86 +2 86 87 +2 87 88 +2 88 89 +2 89 90 +2 90 91 +2 91 92 +2 92 93 +2 93 94 +2 94 95 +2 95 0 +2 3 96 +2 96 97 +2 97 98 +2 98 99 +2 99 100 +2 100 101 +2 101 102 +2 102 103 +2 103 104 +2 104 105 +2 105 106 +2 106 107 +2 107 108 +2 108 109 +2 109 110 +2 110 111 +2 111 112 +2 112 113 +2 113 114 +2 114 2 +2 4 115 +2 115 116 +2 116 117 +2 117 118 +2 118 119 +2 119 120 +2 120 121 +2 121 122 +2 122 123 +2 123 124 +2 124 125 +2 125 126 +2 126 127 +2 127 128 +2 128 129 +2 129 130 +2 130 131 +2 131 132 +2 132 133 +2 133 134 +2 134 135 +2 135 136 +2 136 137 +2 137 138 +2 138 139 +2 139 140 +2 140 141 +2 141 142 +2 142 143 +2 143 144 +2 144 145 +2 145 3 +2 1 146 +2 146 147 +2 147 148 +2 148 149 +2 149 150 +2 150 151 +2 151 152 +2 152 153 +2 153 154 +2 154 155 +2 155 156 +2 156 157 +2 157 158 +2 158 159 +2 159 160 +2 160 161 +2 161 162 +2 162 163 +2 163 164 +2 164 165 +2 165 166 +2 166 167 +2 167 168 +2 168 169 +2 169 170 +2 170 171 +2 171 172 +2 172 173 +2 173 174 +2 174 175 +2 175 176 +2 176 4 +2 6 216 +2 216 217 +2 217 218 +2 218 219 +2 219 220 +2 220 221 +2 221 222 +2 222 223 +2 223 224 +2 224 225 +2 225 226 +2 226 227 +2 227 228 +2 228 229 +2 229 230 +2 230 231 +2 231 232 +2 232 233 +2 233 234 +2 234 235 +2 235 236 +2 236 237 +2 237 238 +2 238 239 +2 239 240 +2 240 241 +2 241 242 +2 242 243 +2 243 244 +2 244 245 +2 245 246 +2 246 247 +2 247 248 +2 248 249 +2 249 250 +2 250 251 +2 251 252 +2 252 253 +2 253 254 +2 254 4 +2 5 255 +2 255 256 +2 256 257 +2 257 258 +2 258 259 +2 259 260 +2 260 261 +2 261 262 +2 262 263 +2 263 264 +2 264 265 +2 265 266 +2 266 267 +2 267 268 +2 268 269 +2 269 270 +2 270 271 +2 271 272 +2 272 273 +2 273 274 +2 274 275 +2 275 276 +2 276 277 +2 277 278 +2 278 279 +2 279 280 +2 280 281 +2 281 282 +2 282 283 +2 283 284 +2 284 285 +2 285 6 +2 6 325 +2 325 326 +2 326 327 +2 327 328 +2 328 329 +2 329 330 +2 330 331 +2 331 332 +2 332 333 +2 333 334 +2 334 335 +2 335 336 +2 336 337 +2 337 338 +2 338 339 +2 339 340 +2 340 341 +2 341 342 +2 342 343 +2 343 344 +2 344 345 +2 345 346 +2 346 347 +2 347 348 +2 348 349 +2 349 350 +2 350 351 +2 351 352 +2 352 353 +2 353 354 +2 354 355 +2 355 7 +2 8 356 +2 356 357 +2 357 358 +2 358 359 +2 359 360 +2 360 361 +2 361 362 +2 362 363 +2 363 364 +2 364 365 +2 365 366 +2 366 367 +2 367 368 +2 368 369 +2 369 370 +2 370 371 +2 371 372 +2 372 373 +2 373 374 +2 374 5 +2 9 375 +2 375 376 +2 376 377 +2 377 378 +2 378 379 +2 379 380 +2 380 381 +2 381 382 +2 382 383 +2 383 384 +2 384 385 +2 385 386 +2 386 387 +2 387 388 +2 388 389 +2 389 390 +2 390 391 +2 391 392 +2 392 393 +2 393 7 +2 8 394 +2 394 395 +2 395 396 +2 396 397 +2 397 398 +2 398 399 +2 399 400 +2 400 401 +2 401 402 +2 402 403 +2 403 404 +2 404 405 +2 405 406 +2 406 407 +2 407 408 +2 408 409 +2 409 410 +2 410 411 +2 411 412 +2 412 413 +2 413 414 +2 414 415 +2 415 416 +2 416 417 +2 417 418 +2 418 419 +2 419 420 +2 420 421 +2 421 422 +2 422 423 +2 423 424 +2 424 425 +2 425 426 +2 426 427 +2 427 428 +2 428 429 +2 429 430 +2 430 431 +2 431 432 +2 432 433 +2 433 434 +2 434 435 +2 435 436 +2 436 437 +2 437 438 +2 438 439 +2 439 440 +2 440 441 +2 441 442 +2 442 443 +2 443 444 +2 444 445 +2 445 446 +2 446 447 +2 447 448 +2 448 449 +2 449 450 +2 450 451 +2 451 452 +2 452 453 +2 453 454 +2 454 455 +2 455 456 +2 456 9 +2 11 457 +2 457 458 +2 458 459 +2 459 460 +2 460 461 +2 461 462 +2 462 463 +2 463 464 +2 464 465 +2 465 466 +2 466 467 +2 467 468 +2 468 469 +2 469 470 +2 470 471 +2 471 472 +2 472 473 +2 473 474 +2 474 475 +2 475 476 +2 476 477 +2 477 478 +2 478 479 +2 479 480 +2 480 481 +2 481 482 +2 482 483 +2 483 484 +2 484 485 +2 485 486 +2 486 487 +2 487 488 +2 488 489 +2 489 490 +2 490 491 +2 491 492 +2 492 493 +2 493 494 +2 494 495 +2 495 10 +2 10 496 +2 496 497 +2 497 498 +2 498 499 +2 499 500 +2 500 501 +2 501 502 +2 502 1 +2 11 503 +2 503 504 +2 504 505 +2 505 506 +2 506 507 +2 507 508 +2 508 509 +2 509 5 +2 3 510 +2 510 511 +2 511 512 +2 512 513 +2 513 514 +2 514 515 +2 515 516 +2 516 12 +2 13 517 +2 517 518 +2 518 519 +2 519 520 +2 520 521 +2 521 522 +2 522 523 +2 523 524 +2 524 525 +2 525 526 +2 526 527 +2 527 528 +2 528 529 +2 529 530 +2 530 531 +2 531 532 +2 532 533 +2 533 534 +2 534 535 +2 535 536 +2 536 537 +2 537 538 +2 538 539 +2 539 540 +2 540 541 +2 541 542 +2 542 543 +2 543 544 +2 544 545 +2 545 546 +2 546 547 +2 547 548 +2 548 549 +2 549 550 +2 550 551 +2 551 552 +2 552 553 +2 553 554 +2 554 555 +2 555 12 +2 7 556 +2 556 557 +2 557 558 +2 558 559 +2 559 560 +2 560 561 +2 561 562 +2 562 13 +3 1004 614 1180 +3 745 1062 1155 +3 1062 638 1155 +3 1501 1158 1725 +3 983 692 1130 +3 1021 834 1219 +3 1095 606 1379 +3 693 1002 1946 +3 607 1094 1371 +3 571 1131 1291 +3 96 3 1358 +3 3 145 1358 +3 976 1082 1891 +3 1082 569 1891 +3 970 586 1664 +3 1011 686 1142 +3 1210 749 1317 +3 160 159 1043 +3 712 1232 1274 +3 1112 743 1205 +3 779 1112 1205 +3 665 960 1571 +3 721 1041 1120 +3 1041 617 1120 +3 1147 1360 1699 +3 1189 1522 1668 +3 968 701 1280 +3 1419 1134 1680 +3 646 1098 1443 +3 1098 841 1443 +3 1015 595 2094 +3 128 127 1068 +3 1106 818 1357 +3 631 1106 1357 +3 689 1114 1272 +3 80 79 1067 +3 712 1136 1232 +3 996 592 1134 +3 1341 635 1789 +3 817 1005 1869 +3 989 821 1145 +3 757 939 1377 +3 1111 814 1467 +3 1048 693 1946 +3 646 1083 1098 +3 1083 724 1098 +3 1103 784 1830 +3 954 35 1365 +3 1201 892 1565 +3 606 1149 1379 +3 609 1119 1177 +3 1119 776 1177 +3 1210 1317 1515 +3 877 1046 1650 +3 1046 587 1650 +3 1088 598 1150 +3 1072 745 1441 +3 1146 607 1371 +3 1092 751 1458 +3 612 1017 1191 +3 1140 863 1237 +3 592 1140 1237 +3 827 1042 1567 +3 697 990 1438 +3 1047 698 1464 +3 1134 592 1680 +3 573 1141 1376 +3 1032 706 1461 +3 939 757 1375 +3 862 1230 1387 +3 698 1049 1464 +3 1141 830 1376 +3 601 977 1863 +3 799 1049 1180 +3 1049 698 1180 +3 595 1105 2094 +3 1218 816 1240 +3 788 1218 1240 +3 626 992 1204 +3 992 727 1204 +3 692 983 1353 +3 1074 689 2134 +3 689 1075 2134 +3 984 692 1353 +3 1233 571 1291 +3 719 1029 1673 +3 993 710 1704 +3 990 697 1168 +3 732 1162 1352 +3 829 1060 1488 +3 1026 722 2076 +3 1230 637 1387 +3 607 1146 1264 +3 843 1501 1725 +3 1042 827 1624 +3 899 1064 1723 +3 719 2015 2068 +3 671 1015 1262 +3 1117 719 2068 +3 1060 673 1488 +3 27 982 1557 +3 1025 714 1149 +3 579 1253 1418 +3 1253 890 1418 +3 82 81 1076 +3 971 720 1215 +3 1572 1193 2151 +3 648 1063 1305 +3 1018 697 1438 +3 629 1448 1684 +3 590 1006 1648 +3 1166 878 1696 +3 887 1073 1498 +3 1073 647 1498 +3 1323 629 1684 +3 1111 1467 1912 +3 1147 625 1360 +3 606 1025 1149 +3 1723 1064 2085 +3 1352 1162 1841 +3 736 992 1236 +3 992 626 1236 +3 1880 1178 2037 +3 1017 797 2059 +3 1023 673 1745 +3 880 1023 1745 +3 1038 746 1157 +3 992 736 1329 +3 565 1027 1507 +3 618 1159 1633 +3 1005 1222 1869 +3 1007 678 1480 +3 614 959 1844 +3 156 978 1627 +3 723 1178 1880 +3 701 1201 1565 +3 1042 764 1257 +3 620 1042 1257 +3 593 1193 1572 +3 1068 127 1532 +3 50 990 1593 +3 745 1155 1441 +3 1006 590 1845 +3 632 1269 1316 +3 1269 855 1316 +3 1328 929 1612 +3 1037 565 1507 +3 1398 1186 2009 +3 1215 618 1633 +3 1048 712 1274 +3 959 614 1607 +3 35 954 1810 +3 706 1032 2090 +3 983 125 1353 +3 727 980 1204 +3 1264 1146 1645 +3 722 1103 2076 +3 690 1186 1398 +3 80 1067 1509 +3 722 1026 1281 +3 1286 1581 1898 +3 593 1010 1374 +3 751 1243 1458 +3 602 1104 1173 +3 1104 760 1173 +3 1273 576 1351 +3 869 1273 1351 +3 1189 699 1522 +3 1024 715 1219 +3 1139 1409 1740 +3 625 1147 1395 +3 1147 831 1395 +3 1150 598 1925 +3 1037 840 1759 +3 1286 744 1581 +3 1129 796 1315 +3 1461 706 2138 +3 765 1125 1185 +3 1383 140 1637 +3 966 653 1389 +3 652 1328 1612 +3 907 1363 1486 +3 1019 859 1454 +3 1359 860 1602 +3 775 1010 1476 +3 609 1213 1817 +3 1035 601 1751 +3 720 971 1447 +3 960 665 1482 +3 1485 1300 1639 +3 1000 781 1427 +3 1011 133 1380 +3 1139 792 1409 +3 1213 609 1857 +3 813 1300 1485 +3 1672 738 1813 +3 624 1271 1354 +3 1029 719 2071 +3 160 1043 1456 +3 701 968 1534 +3 633 1234 1535 +3 653 966 1928 +3 101 1216 1618 +3 1535 1234 1826 +3 617 1041 2146 +3 1268 656 1614 +3 128 1068 1266 +3 587 1046 1951 +3 1375 912 1501 +3 176 1056 1884 +3 799 1030 1478 +3 797 1107 2059 +3 1188 670 1523 +3 598 1088 2148 +3 1010 593 1199 +3 893 1188 1523 +3 860 1359 2018 +3 586 970 1293 +3 1096 804 1252 +3 677 1096 1252 +3 699 980 2143 +3 1061 601 1863 +3 1138 719 1673 +3 622 1013 1206 +3 112 987 1494 +3 1124 648 1305 +3 1113 706 2090 +3 785 988 1451 +3 988 673 1451 +3 798 1135 1249 +3 135 134 1142 +3 1198 786 1206 +3 718 1198 1206 +3 773 1116 1312 +3 721 1721 1914 +3 1363 654 1486 +3 1454 859 1890 +3 1354 1271 1719 +3 1214 1669 2103 +3 966 605 1436 +3 605 966 1720 +3 1214 582 1669 +3 986 762 1457 +3 722 1118 1332 +3 569 1082 2105 +3 1196 721 1914 +3 914 1103 1830 +3 912 1158 1501 +3 1013 718 1206 +3 4 176 1884 +3 1097 795 1468 +3 1076 81 1509 +3 849 999 1766 +3 809 1028 1497 +3 1028 663 1497 +3 881 1341 1789 +3 721 1092 1897 +3 705 1027 1405 +3 930 1245 1389 +3 1245 766 1389 +3 716 1088 1150 +3 1053 630 1337 +3 643 1187 1408 +3 1187 842 1408 +3 70 1267 1394 +3 1065 633 1251 +3 763 1065 1251 +3 730 1733 1805 +3 708 1006 1230 +3 1310 1650 2032 +3 1005 669 1222 +3 1571 960 1936 +3 980 727 1559 +3 1067 1461 2138 +3 692 984 1813 +3 1232 786 1274 +3 1462 1037 1759 +3 1143 617 2146 +3 1041 721 1196 +3 979 663 1294 +3 135 1142 1655 +3 977 752 1367 +3 783 1354 1415 +3 1354 919 1415 +3 712 1048 1946 +3 1272 1114 1473 +3 1449 628 1483 +3 752 977 1343 +3 977 601 1343 +3 1165 570 1424 +3 838 1165 1424 +3 709 1539 1989 +3 1085 722 1281 +3 1232 1136 1611 +3 1044 1571 1936 +3 1199 956 1743 +3 991 621 1259 +3 1092 721 2147 +3 1040 705 1405 +3 742 1033 1221 +3 1033 675 1221 +3 719 1117 2071 +3 735 1081 1185 +3 1081 581 1185 +3 1090 597 1936 +3 960 1090 1936 +3 727 992 1270 +3 917 1649 1861 +3 695 1057 1421 +3 601 1061 2000 +3 1250 731 1261 +3 817 1250 1261 +3 978 156 1429 +3 1625 1977 2132 +3 1042 620 1567 +3 71 70 1394 +3 704 1199 1743 +3 1319 1576 1934 +3 1055 726 1957 +3 566 1375 1501 +3 698 1047 2084 +3 1183 730 1805 +3 770 1143 1169 +3 1027 565 1828 +3 137 1314 1361 +3 1721 721 1897 +3 1977 695 2132 +3 24 25 1093 +3 1178 829 1488 +3 1057 695 1977 +3 1171 29 1605 +3 17 1170 1606 +3 718 1013 1795 +3 568 1012 1569 +3 1804 1235 1930 +3 794 1086 1657 +3 1279 166 2067 +3 580 1153 1484 +3 1153 858 1484 +3 726 1055 1910 +3 23 1570 1617 +3 1073 768 1433 +3 984 1672 1813 +3 755 1024 2135 +3 816 1034 1240 +3 1034 615 1240 +3 1012 676 1510 +3 1341 1646 1840 +3 570 1723 2085 +3 1030 799 1836 +3 1059 755 1247 +3 575 1059 1247 +3 1028 608 1401 +3 785 987 1643 +3 999 849 1708 +3 608 1028 1587 +3 970 1664 2070 +3 1319 752 1576 +3 990 50 1438 +3 709 1123 1539 +3 1061 726 1910 +3 696 1416 1732 +3 997 782 1289 +3 28 29 1171 +3 17 18 1170 +3 1007 1480 1656 +3 1076 691 1893 +3 1178 1488 1806 +3 575 1169 1352 +3 755 1059 1521 +3 878 1166 1842 +3 736 1235 1804 +3 1462 638 1592 +3 722 1332 1769 +3 1049 799 1478 +3 1010 687 1374 +3 1704 710 2025 +3 674 1000 1687 +3 564 1235 1282 +3 1235 811 1282 +3 1013 742 1256 +3 1227 564 1282 +3 808 1227 1282 +3 1310 877 1650 +3 724 1105 1662 +3 575 1352 1794 +3 683 1197 1853 +3 1275 38 1824 +3 963 1290 2062 +3 1054 667 1678 +3 861 1054 1678 +3 1086 699 1189 +3 577 1089 1439 +3 1219 834 1812 +3 671 1042 1624 +3 1079 738 1370 +3 599 1111 2082 +3 1111 1014 2082 +3 784 1103 1769 +3 101 100 1216 +3 590 1648 1919 +3 821 989 1634 +3 1025 606 1309 +3 754 1025 1309 +3 131 1577 1706 +3 1260 760 1690 +3 1570 961 1617 +3 1341 762 1646 +3 760 1302 1690 +3 1016 85 1686 +3 1250 624 1468 +3 1025 754 1263 +3 1024 755 1264 +3 742 1013 1772 +3 1293 809 1497 +3 737 1044 1265 +3 1751 601 2000 +3 614 1004 1607 +3 1058 828 1363 +3 790 1445 1729 +3 621 991 1334 +3 709 1573 2074 +3 804 1034 1552 +3 798 978 1429 +3 978 798 1746 +3 1123 667 1858 +3 952 1123 1858 +3 1031 650 1324 +3 986 115 1884 +3 1148 623 1349 +3 1100 631 1357 +3 790 1100 1357 +3 1085 619 1217 +3 727 1019 1559 +3 1957 726 2093 +3 758 998 1323 +3 1176 800 1823 +3 663 979 1497 +3 714 1025 1784 +3 982 27 1551 +3 754 1050 1285 +3 1050 574 1285 +3 724 1662 1694 +3 1293 1497 2021 +3 573 1376 1559 +3 1376 980 1559 +3 1039 1825 1853 +3 728 1069 1877 +3 1045 602 1373 +3 1360 853 1699 +3 602 1045 1871 +3 665 1701 1927 +3 1397 822 1426 +3 628 1263 1483 +3 592 996 1635 +3 1825 683 1853 +3 1007 850 1718 +3 828 1058 1574 +3 1058 596 1574 +3 1013 622 1772 +3 981 771 1479 +3 987 785 1487 +3 650 1031 1493 +3 819 1108 1459 +3 1108 621 1459 +3 1538 1111 1906 +3 578 1342 1778 +3 771 981 1505 +3 1184 964 1811 +3 151 150 1152 +3 676 1012 1302 +3 1043 791 1456 +3 1122 698 2084 +3 1250 1468 2061 +3 604 1162 1761 +3 1043 159 1330 +3 1143 732 1169 +3 687 1010 1727 +3 125 983 1892 +3 1107 797 1469 +3 980 699 1561 +3 859 1019 1764 +3 1019 727 1764 +3 607 1264 1714 +3 1577 985 1706 +3 812 1068 1532 +3 1520 1054 1735 +3 988 785 1382 +3 616 1184 1811 +3 1123 952 1539 +3 1264 1521 1714 +3 567 1166 1696 +3 1197 963 1853 +3 1102 566 1471 +3 91 90 1154 +3 1200 650 1675 +3 935 1200 1675 +3 565 1205 1742 +3 1067 807 1509 +3 735 1026 1511 +3 148 1231 1834 +3 980 1376 2143 +3 1262 1015 2094 +3 733 1482 1568 +3 85 1016 1450 +3 743 1112 1223 +3 1521 1059 1851 +3 1030 1279 2067 +3 1128 688 1337 +3 762 986 1428 +3 82 1076 1320 +3 1034 804 1584 +3 1125 735 1185 +3 700 1124 2045 +3 1086 1189 1657 +3 1573 709 1940 +3 1129 1315 1589 +3 1196 604 1761 +3 617 1109 1364 +3 728 1527 1670 +3 622 1033 1772 +3 857 1266 1546 +3 1825 991 1888 +3 1168 697 1419 +3 1224 93 1827 +3 1229 802 1356 +3 1087 733 1298 +3 1212 762 1341 +3 881 1212 1341 +3 935 1675 1842 +3 1180 698 1962 +3 1004 1180 1962 +3 1250 817 1271 +3 624 1250 1271 +3 1058 730 1295 +3 882 1268 1614 +3 565 1742 1828 +3 1292 738 1672 +3 115 986 1457 +3 594 1048 1274 +3 142 141 1161 +3 807 1067 2138 +3 1173 760 1174 +3 756 1173 1174 +3 1257 764 1325 +3 824 1257 1325 +3 1290 963 1862 +3 1101 958 1965 +3 684 1101 1965 +3 1075 574 2106 +3 1320 1076 1893 +3 946 1572 2151 +3 681 1043 1801 +3 1181 589 1638 +3 987 112 1643 +3 630 1053 1444 +3 722 1085 2129 +3 765 1185 1303 +3 710 993 1550 +3 1088 716 2056 +3 1069 728 1594 +3 1124 1305 2045 +3 1139 670 1188 +3 1337 688 2099 +3 792 1139 1188 +3 673 988 1745 +3 997 1351 1700 +3 1002 693 2072 +3 564 1227 1256 +3 1312 1116 1705 +3 1033 742 1772 +3 945 1294 1821 +3 64 63 1121 +3 1351 576 1700 +3 1106 704 1208 +3 1000 674 1604 +3 1047 1456 2084 +3 1546 1266 2155 +3 1140 675 1757 +3 89 88 1164 +3 760 1104 1302 +3 1006 708 1648 +3 1193 593 1374 +3 998 758 1412 +3 764 1031 1324 +3 596 1058 1295 +3 1010 1199 1476 +3 999 795 1410 +3 1100 731 1466 +3 660 1399 1421 +3 1399 917 1421 +3 814 1111 1538 +3 1539 1020 1989 +3 1297 712 1946 +3 1097 1468 1855 +3 1289 898 1815 +3 769 1018 1344 +3 835 1078 1258 +3 1078 779 1258 +3 1087 571 1233 +3 1033 622 1756 +3 675 1033 1757 +3 1125 619 1785 +3 678 1007 1422 +3 1136 712 1297 +3 751 1092 2147 +3 1342 936 1778 +3 824 1137 1257 +3 1137 620 1257 +3 807 1076 1509 +3 1191 1017 1715 +3 771 1028 1401 +3 1107 1469 1749 +3 1028 809 1587 +3 1034 669 1552 +3 871 1383 1637 +3 949 1705 2014 +3 694 1090 1750 +3 1012 568 1690 +3 1202 793 1247 +3 1400 948 1482 +3 665 1400 1482 +3 782 997 1700 +3 729 1110 1214 +3 1079 692 1813 +3 1035 713 1932 +3 1158 640 1243 +3 997 1289 1815 +3 713 1035 1751 +3 1032 1427 2090 +3 1034 816 1597 +3 669 1034 1597 +3 1398 1473 2142 +3 1216 868 1618 +3 1005 817 1752 +3 1082 976 1991 +3 767 1011 1380 +3 1398 845 1473 +3 795 999 1468 +3 1701 972 1927 +3 94 93 1224 +3 1017 612 1516 +3 797 1017 1516 +3 1118 722 2129 +3 892 1201 1937 +3 1213 923 1430 +3 1202 755 2135 +3 1471 566 1501 +3 628 1203 1263 +3 776 1119 1217 +3 148 147 1231 +3 856 1096 1621 +3 1096 677 1621 +3 781 1000 1604 +3 1222 1958 1975 +3 1315 655 1503 +3 915 1315 1503 +3 1522 831 1668 +3 151 1152 1870 +3 923 1213 1857 +3 1482 948 1568 +3 1222 669 1958 +3 153 152 1175 +3 850 1007 1656 +3 748 1119 2108 +3 1044 737 1797 +3 574 1118 2106 +3 1060 829 1630 +3 1213 909 1817 +3 1219 715 2079 +3 728 1877 2102 +3 1112 610 1223 +3 1031 764 1712 +3 904 1538 1906 +3 802 1229 1322 +3 686 1011 1490 +3 39 38 1275 +3 51 50 1593 +3 1226 1550 1984 +3 1124 700 1253 +3 1527 973 1670 +3 1120 751 2147 +3 167 166 1279 +3 694 1750 2086 +3 701 1200 1280 +3 748 2108 2134 +3 1667 637 1848 +3 669 1005 1552 +3 1638 589 1864 +3 656 1268 1724 +3 26 27 1557 +3 1273 883 1611 +3 1122 612 1241 +3 1314 853 1360 +3 801 1314 1360 +3 1010 775 1727 +3 619 1085 1281 +3 53 52 1138 +3 1154 90 1860 +3 1046 680 1368 +3 1063 794 1305 +3 746 1038 1347 +3 1226 710 1550 +3 786 1198 1274 +3 1198 594 1274 +3 922 1176 1823 +3 91 1154 1308 +3 15 16 1126 +3 30 31 1127 +3 1006 802 1470 +3 802 1006 1845 +3 595 1015 1623 +3 1015 671 1624 +3 133 1011 1895 +3 697 1018 1518 +3 751 1120 1287 +3 811 1235 1236 +3 1235 736 1236 +3 885 1220 1529 +3 1208 563 1533 +3 987 1487 1640 +3 638 1339 1592 +3 1089 577 2013 +3 565 1037 1703 +3 1407 806 1667 +3 1159 807 2138 +3 606 1095 1771 +3 1110 729 2154 +3 1144 744 1730 +3 1026 735 1785 +3 1002 1297 1946 +3 137 136 1314 +3 1053 1337 2099 +3 940 1275 1824 +3 632 1229 1356 +3 21 22 1133 +3 1416 938 1732 +3 884 1208 1743 +3 1152 150 1318 +3 129 128 1266 +3 1016 796 1450 +3 142 1161 1689 +3 979 1683 1803 +3 1066 763 2017 +3 1333 107 1479 +3 1011 767 1490 +3 759 1262 2094 +3 1028 771 1505 +3 1510 676 1793 +3 675 1140 1634 +3 1539 952 1993 +3 840 1037 1711 +3 1054 1520 2130 +3 744 1164 1730 +3 644 1145 1513 +3 1175 903 1299 +3 747 1175 1299 +3 615 1096 1663 +3 1825 1039 2148 +3 581 1081 1949 +3 726 1061 1863 +3 1265 926 1321 +3 747 1151 1773 +3 1177 725 2004 +3 724 1083 2019 +3 1062 745 1591 +3 1164 744 1286 +3 900 1164 1286 +3 58 57 1190 +3 752 1077 1367 +3 834 1021 1774 +3 1331 864 1402 +3 674 1331 1402 +3 1042 671 1712 +3 619 1281 1785 +3 157 156 1627 +3 107 106 1479 +3 768 1276 1433 +3 1487 662 1640 +3 571 1087 1298 +3 1021 1219 2079 +3 796 1016 1831 +3 1179 780 1291 +3 713 1179 1291 +3 566 1102 2097 +3 715 1024 1645 +3 62 1284 1868 +3 1255 629 1323 +3 1048 594 2011 +3 851 1171 1605 +3 1170 852 1606 +3 1594 728 1670 +3 759 1244 1658 +3 1270 992 1329 +3 1065 763 1867 +3 763 1066 1867 +3 704 1106 2125 +3 845 1398 2009 +3 1018 769 1518 +3 1077 752 1319 +3 782 1297 1350 +3 1416 696 1679 +3 637 1322 1848 +3 1157 746 1837 +3 1251 870 1575 +3 1029 54 1673 +3 1200 1565 1959 +3 1262 759 1658 +3 795 1097 2052 +3 568 1569 1966 +3 1155 840 1441 +3 1175 747 1773 +3 691 1076 1911 +3 54 1029 1653 +3 1096 856 1663 +3 673 1023 1488 +3 680 1046 1428 +3 1128 839 1536 +3 587 1128 1536 +3 764 1042 1712 +3 1098 724 1342 +3 1023 880 1709 +3 1129 603 1581 +3 1503 918 1949 +3 1750 1087 2086 +3 89 1164 1860 +3 1043 681 1713 +3 1359 975 2018 +3 818 1234 1357 +3 1234 790 1357 +3 1142 853 1655 +3 1650 934 2032 +3 1249 1135 1603 +3 1027 705 1507 +3 948 1582 1663 +3 41 40 1195 +3 1081 1503 1949 +3 610 1112 2150 +3 738 1248 1370 +3 663 1028 1505 +3 1294 663 1821 +3 1857 1177 2004 +3 966 1389 1720 +3 1349 1110 2154 +3 1215 1770 2113 +3 615 1034 1584 +3 686 1052 1388 +3 999 1410 1766 +3 1641 19 1774 +3 117 116 1212 +3 1579 104 1619 +3 601 1035 1575 +3 1321 926 1846 +3 756 1631 2008 +3 2015 998 2068 +3 604 1135 1541 +3 612 1191 1241 +3 1455 809 1777 +3 1205 565 1258 +3 779 1205 1258 +3 991 1259 1888 +3 1478 1030 2067 +3 707 1865 2075 +3 967 1880 2037 +3 751 1158 1243 +3 1090 694 2003 +3 1165 734 2001 +3 1166 567 1254 +3 1021 1641 1774 +3 1391 1039 2062 +3 1231 932 1834 +3 1105 724 2019 +3 1287 617 1364 +3 1200 701 1565 +3 693 1048 1417 +3 1215 720 1770 +3 1052 686 1490 +3 1865 707 2104 +3 1160 606 1771 +3 1251 1575 1916 +3 1417 935 1842 +3 1094 607 1348 +3 1328 652 1843 +3 943 1373 1807 +3 1409 582 1740 +3 741 1391 2062 +3 705 1040 1905 +3 925 1224 1827 +3 66 65 1218 +3 1456 791 2084 +3 1359 583 1416 +3 876 1359 1416 +3 133 132 1380 +3 1059 575 1794 +3 638 1062 1809 +3 899 1191 1715 +3 576 1273 1611 +3 574 1050 2118 +3 1208 1533 1994 +3 66 1218 1372 +3 1649 625 1861 +3 1493 1031 1917 +3 891 1071 1973 +3 745 1072 1865 +3 1046 877 1646 +3 577 1246 1312 +3 668 1107 1722 +3 1107 872 1722 +3 1674 864 2066 +3 1120 617 1287 +3 864 1331 2066 +3 1125 765 1288 +3 1106 631 1307 +3 1054 861 1735 +3 1679 951 1843 +3 575 1084 1995 +3 1175 152 1870 +3 597 1090 1950 +3 1056 810 1596 +3 62 61 1284 +3 1529 1220 1811 +3 809 1293 1777 +3 1439 775 1548 +3 1190 930 2116 +3 630 1077 1894 +3 683 1825 1888 +3 1154 900 1283 +3 619 1125 1288 +3 1192 951 1679 +3 1430 923 1944 +3 1726 1384 1926 +3 75 1311 2043 +3 1763 778 2124 +3 1145 644 1639 +3 1081 735 1879 +3 1207 614 1844 +3 1314 801 1361 +3 890 1839 2136 +3 1077 630 1367 +3 1208 884 1929 +3 1174 654 1875 +3 766 1653 2071 +3 791 1043 1713 +3 1141 695 2030 +3 975 1799 2018 +3 1434 1190 2116 +3 1131 713 1291 +3 783 1097 1855 +3 1060 1630 1986 +3 1097 783 1434 +3 653 1097 1434 +3 1145 821 1513 +3 1209 933 1514 +3 802 1322 1470 +3 1445 886 1729 +3 969 1329 1804 +3 822 1306 1426 +3 1168 1419 1616 +3 762 1212 1457 +3 750 1154 1283 +3 1631 1080 2008 +3 913 1407 1667 +3 581 1520 1735 +3 1173 756 1807 +3 144 143 1211 +3 789 1352 1841 +3 1070 674 1960 +3 1050 754 1852 +3 1152 903 1870 +3 901 1184 1411 +3 1172 893 1523 +3 1389 766 1720 +3 782 1136 1297 +3 1091 630 1894 +3 1180 614 1776 +3 721 1120 2147 +3 1152 753 1393 +3 1413 174 1698 +3 1723 1165 2001 +3 1156 120 1798 +3 1182 636 1839 +3 763 1131 2017 +3 1084 678 1430 +3 582 1214 1338 +3 842 1521 1851 +3 730 1058 1733 +3 1107 668 2059 +3 756 1153 1631 +3 1130 620 1563 +3 1837 746 2078 +3 1099 679 1836 +3 1441 840 2063 +3 951 1328 1843 +3 1265 1044 1936 +3 1104 602 1871 +3 897 1104 1871 +3 1148 1349 1753 +3 623 1078 1519 +3 1007 1718 1956 +3 1051 1957 2093 +3 900 1154 1860 +3 755 1202 1247 +3 1093 25 1676 +3 600 1132 1996 +3 1132 944 1996 +3 563 1276 1691 +3 1799 679 2018 +3 673 1060 1451 +3 716 1334 2056 +3 908 1156 1517 +3 766 1245 1653 +3 964 1184 1732 +3 768 1073 1481 +3 1427 781 2090 +3 64 1121 1549 +3 770 1169 1995 +3 44 43 1209 +3 1190 57 1931 +3 1174 760 1486 +3 713 1131 1932 +3 1224 703 2121 +3 702 1231 2122 +3 1818 1327 1918 +3 1197 683 1888 +3 117 1212 1762 +3 1207 860 1598 +3 125 124 1353 +3 1272 845 1449 +3 815 1272 1449 +3 1456 1047 2109 +3 855 1269 1437 +3 667 1054 1564 +3 1118 574 1332 +3 1142 686 1699 +3 647 1073 1433 +3 780 1179 1335 +3 1179 610 1335 +3 680 1108 1368 +3 577 1439 1766 +3 1109 725 1364 +3 1102 725 2139 +3 1334 825 1459 +3 731 1100 1971 +3 810 1056 1504 +3 1427 1032 2077 +3 583 1359 1602 +3 1056 176 1504 +3 597 1265 1936 +3 1319 563 1691 +3 1067 79 1461 +3 1019 1454 1652 +3 1454 847 1652 +3 1246 795 1278 +3 796 1144 1947 +3 119 118 1336 +3 1329 736 1804 +3 1184 696 1732 +3 1208 704 1743 +3 1161 862 1689 +3 634 1313 1590 +3 738 1079 1813 +3 574 1075 1850 +3 1154 750 1308 +3 1114 689 1903 +3 909 1114 1903 +3 1200 935 1280 +3 847 1454 1590 +3 1086 794 1492 +3 1185 581 1303 +3 1045 1373 1609 +3 753 1187 1393 +3 1119 609 2108 +3 1195 761 1345 +3 75 74 1311 +3 1100 790 1378 +3 863 1140 1757 +3 1229 632 1423 +3 1088 1825 2148 +3 1350 1297 2041 +3 1705 661 2014 +3 794 1063 1492 +3 1078 835 2034 +3 1068 812 1477 +3 113 112 1494 +3 623 1110 1349 +3 753 1152 1318 +3 1346 803 1528 +3 1794 789 1851 +3 1064 899 1882 +3 1164 900 1860 +3 730 1242 1295 +3 635 1397 1426 +3 945 1579 1619 +3 781 1070 1835 +3 600 1327 1818 +3 1582 615 1663 +3 711 1446 2002 +3 1109 617 1822 +3 1351 997 1815 +3 1059 1794 1851 +3 775 1089 1727 +3 1284 941 1868 +3 695 1421 2030 +3 852 1146 1371 +3 1527 728 2102 +3 706 1113 2065 +3 800 1176 1838 +3 92 91 1308 +3 839 1128 1337 +3 989 1145 1537 +3 1117 605 1720 +3 1063 648 1661 +3 700 1181 1638 +3 1076 807 1911 +3 1070 781 1604 +3 1149 851 1379 +3 1071 891 1721 +3 1182 700 1638 +3 633 1065 1987 +3 689 1074 1903 +3 1075 689 1474 +3 1590 1313 2070 +3 1009 1224 2121 +3 1108 819 1368 +3 1078 623 1472 +3 1302 1104 1992 +3 1278 653 1928 +3 1544 1133 1717 +3 605 1117 2068 +3 1089 775 1439 +3 1756 1238 1808 +3 943 1326 1373 +3 1329 969 1574 +3 1161 141 1383 +3 1103 914 1974 +3 690 1398 1704 +3 1398 993 1704 +3 775 1307 1548 +3 1000 1427 2043 +3 818 1106 1994 +3 41 1195 1345 +3 844 1145 1639 +3 779 1078 1472 +3 1231 1008 2122 +3 1121 816 1549 +3 616 1220 1838 +3 1510 723 1569 +3 1012 1510 1569 +3 35 34 1365 +3 1043 1330 1801 +3 150 149 1318 +3 800 1223 1780 +3 85 84 1686 +3 654 1620 1875 +3 1290 741 2062 +3 940 1347 1697 +3 1342 724 1694 +3 1630 588 1986 +3 1251 633 1535 +3 870 1251 1535 +3 1683 855 1803 +3 1298 733 1568 +3 1311 1000 2043 +3 1374 687 1651 +3 1218 788 1372 +3 903 1175 1870 +3 833 1275 1697 +3 758 1351 1815 +3 1390 1141 2030 +3 1166 693 1842 +3 1000 1311 1687 +3 1195 40 1601 +3 1558 1063 1661 +3 979 1294 1683 +3 702 1371 1988 +3 1371 1094 1988 +3 678 1084 1480 +3 811 1558 1661 +3 1462 835 1703 +3 1095 1379 1981 +3 1379 703 1981 +3 1520 805 2130 +3 674 1070 1604 +3 767 1384 1726 +3 692 1079 1500 +3 1037 1462 1703 +3 1049 1478 2141 +3 73 72 1362 +3 1187 643 1393 +3 905 1327 1594 +3 83 82 1320 +3 942 1493 1917 +3 773 1246 1278 +3 1073 887 1943 +3 617 1143 1822 +3 944 1132 1499 +3 1084 575 1547 +3 717 1273 1489 +3 1273 869 1489 +3 1252 804 1553 +3 1083 646 1495 +3 768 1481 1894 +3 1255 1323 2015 +3 772 1216 2024 +3 140 139 1637 +3 776 1217 1340 +3 2108 1074 2134 +3 1169 575 1995 +3 1203 982 2044 +3 714 1203 2044 +3 725 1109 2004 +3 1110 623 1519 +3 1327 600 1594 +3 1256 1227 1795 +3 1865 1072 2075 +3 98 97 1407 +3 1141 573 2117 +3 1151 798 1887 +3 1481 1091 1894 +3 1123 709 2074 +3 1337 630 1744 +3 918 1406 1520 +3 1334 716 1526 +3 1373 602 1807 +3 1406 805 1520 +3 743 1223 1442 +3 780 1233 1291 +3 778 1385 2124 +3 1807 756 2008 +3 839 1091 2049 +3 760 1260 1486 +3 1363 828 1543 +3 1082 1865 2104 +3 965 1141 2117 +3 989 1537 1878 +3 1282 811 1661 +3 175 174 1413 +3 1219 627 2135 +3 1024 1219 2135 +3 1385 947 1625 +3 659 1385 1625 +3 732 1143 2146 +3 2 114 1608 +3 33 2 1608 +3 622 1206 1381 +3 895 1183 1524 +3 1346 1528 1716 +3 725 1177 2139 +3 733 1087 1750 +3 957 1510 1793 +3 985 1577 1613 +3 1191 734 2158 +3 1446 711 1969 +3 1294 945 2089 +3 831 1147 1388 +3 1147 686 1388 +3 930 1190 1931 +3 1242 859 1295 +3 131 130 1577 +3 1347 658 1697 +3 749 1210 1900 +3 109 108 1414 +3 1480 793 1656 +3 1317 838 1425 +3 641 1317 1425 +3 1114 909 1422 +3 681 1268 1431 +3 1268 882 1431 +3 103 102 1239 +3 636 1182 1926 +3 1090 960 2048 +3 631 1100 1466 +3 622 1238 1756 +3 1169 732 1352 +3 1101 684 1463 +3 1554 833 1697 +3 630 1091 1744 +3 1091 839 1744 +3 834 1544 1717 +3 1096 615 1584 +3 695 1141 2132 +3 1141 965 2132 +3 890 1182 1839 +3 958 1101 1556 +3 955 1166 2002 +3 635 1426 1789 +3 699 1086 1561 +3 120 119 1798 +3 802 1277 1356 +3 829 1178 1560 +3 1178 723 1560 +3 1554 1045 1609 +3 833 1554 1609 +3 1401 608 1806 +3 1023 1401 1806 +3 812 1892 1985 +3 1156 787 1517 +3 56 55 1245 +3 853 1142 1699 +3 1126 16 1606 +3 30 1127 1605 +3 1318 932 1800 +3 1194 655 1736 +3 1569 1003 1966 +3 21 1133 1544 +3 1116 773 1436 +3 830 1141 1390 +3 1298 856 1938 +3 1573 995 2074 +3 936 1342 1694 +3 1212 881 1762 +3 1228 765 1452 +3 778 1269 1356 +3 879 1194 1736 +3 1206 786 1381 +3 1126 1606 1874 +3 1299 643 2020 +3 577 1312 2013 +3 725 1102 1471 +3 842 1187 1714 +3 1433 884 1555 +3 1466 731 1708 +3 1277 778 1356 +3 1187 753 1348 +3 1097 653 2052 +3 1217 619 1340 +3 1390 917 1861 +3 596 1329 1574 +3 1565 920 1959 +3 1605 1127 1876 +3 616 1176 1411 +3 910 1197 1888 +3 1139 865 1754 +3 670 1139 1754 +3 856 1621 1938 +3 1334 991 2056 +3 1577 857 1613 +3 1166 955 2072 +3 693 1166 2072 +3 1416 583 1580 +3 938 1416 1580 +3 903 1152 1393 +3 621 1334 1459 +3 1136 576 1611 +3 1246 773 1312 +3 1764 1270 1779 +3 1134 697 1518 +3 1469 584 1749 +3 1241 1191 2158 +3 1581 603 1974 +3 583 1210 1580 +3 1210 854 1580 +3 1712 671 1917 +3 159 158 1330 +3 697 1134 1419 +3 1229 772 1322 +3 1369 772 2024 +3 1839 1022 2136 +3 1514 933 1998 +3 1220 1442 1838 +3 1184 616 1411 +3 928 1350 1681 +3 1247 793 1547 +3 1367 630 1444 +3 1675 878 1842 +3 804 1096 1584 +3 24 1093 1570 +3 1243 640 1731 +3 1267 737 1394 +3 792 1188 1508 +3 585 1261 1378 +3 643 1866 2020 +3 1304 1889 1976 +3 667 1123 2137 +3 651 1321 1846 +3 941 1121 1868 +3 1121 63 1868 +3 847 1734 2117 +3 727 1270 1764 +3 716 1150 1796 +3 1014 1111 1912 +3 1362 72 1902 +3 1418 890 2136 +3 1463 800 1780 +3 1111 599 1906 +3 1382 785 1643 +3 912 1375 2069 +3 1131 571 2017 +3 1211 862 1387 +3 841 1098 1768 +3 1114 591 1473 +3 679 1099 1598 +3 737 1265 1321 +3 1207 1598 2126 +3 1450 796 1947 +3 1350 613 1681 +3 676 1302 1992 +3 874 1221 1660 +3 1221 675 1660 +3 1268 873 1724 +3 1140 821 1634 +3 889 1193 1374 +3 1167 777 1585 +3 1064 1527 2102 +3 1119 748 2022 +3 1346 887 1545 +3 578 1346 1545 +3 1167 716 1796 +3 833 1195 1601 +3 1092 1458 1897 +3 1458 584 1897 +3 1223 800 1442 +3 1104 897 1992 +3 564 1256 1677 +3 1669 1001 2103 +3 1368 819 1583 +3 596 1270 1329 +3 1176 777 1411 +3 793 1202 1420 +3 1202 627 1420 +3 910 1413 1698 +3 789 1841 1866 +3 791 1115 1901 +3 1209 43 1921 +3 983 1130 1985 +3 1103 722 1769 +3 765 1303 1452 +3 743 1220 1742 +3 1220 885 1742 +3 894 1248 1707 +3 1248 645 1707 +3 1192 901 1925 +3 698 1122 1962 +3 604 1541 2027 +3 171 170 1290 +3 1606 852 1874 +3 812 1532 1892 +3 623 1148 2073 +3 1115 791 1713 +3 50 49 1438 +3 1230 1006 1470 +3 1263 1203 1784 +3 1408 789 1866 +3 1283 642 1491 +3 1506 1282 1661 +3 685 1137 1632 +3 1137 824 1632 +3 1304 905 1889 +3 956 1199 1907 +3 1366 642 1830 +3 1581 914 1898 +3 905 1304 1327 +3 1124 892 1937 +3 648 1124 1937 +3 619 1288 1340 +3 1325 579 1418 +3 824 1325 1418 +3 1475 647 1883 +3 851 1605 1876 +3 797 1431 1469 +3 1431 882 1469 +3 856 1298 1568 +3 918 1194 1406 +3 119 1336 1798 +3 1354 783 1855 +3 1400 665 1927 +3 639 1228 1452 +3 1373 761 1609 +3 883 1238 1381 +3 1276 884 1433 +3 1836 679 2100 +3 98 1407 1913 +3 1166 1254 2002 +3 1194 691 1406 +3 115 4 1884 +3 42 41 1345 +3 1136 782 1700 +3 753 1318 1800 +3 872 1107 1749 +3 1115 681 2046 +3 815 1449 1483 +3 778 1277 1542 +3 1304 757 1327 +3 1105 595 1662 +3 678 1213 1430 +3 1550 850 1984 +3 929 1328 1970 +3 612 1122 1901 +3 835 1462 1592 +3 1135 604 1603 +3 1546 685 1632 +3 1022 1546 1632 +3 806 1211 1387 +3 1148 694 1465 +3 37 36 1301 +3 1137 685 1477 +3 1377 639 1573 +3 902 1377 1573 +3 1221 874 1610 +3 1877 1036 2102 +3 1252 1553 1859 +3 1210 1602 1900 +3 1591 745 1991 +3 1248 894 1370 +3 901 1192 1999 +3 1108 680 1596 +3 621 1108 1595 +3 1231 702 1988 +3 1437 1269 1763 +3 637 1230 1470 +3 86 85 1450 +3 1587 967 2037 +3 807 1163 1911 +3 15 1126 1923 +3 1127 31 1922 +3 1131 763 1932 +3 892 1124 1952 +3 1576 911 1934 +3 1158 912 1976 +3 640 1158 1976 +3 1455 967 1587 +3 1463 684 1823 +3 1718 591 1956 +3 1288 820 1340 +3 889 1374 1651 +3 1041 1196 1761 +3 796 1129 1941 +3 169 1396 1767 +3 1391 598 2148 +3 1830 642 1898 +3 933 1209 1921 +3 1437 962 1664 +3 586 1437 1664 +3 1172 1523 1891 +3 156 155 1429 +3 1183 895 1873 +3 730 1183 1873 +3 1417 1048 2011 +3 830 1395 1522 +3 684 1692 1823 +3 647 1433 1555 +3 783 1190 1434 +3 703 1224 1981 +3 1199 704 1476 +3 1038 1157 1588 +3 1130 1563 1985 +3 787 1156 1798 +3 1112 779 1642 +3 1260 907 1486 +3 1163 618 1710 +3 1254 896 1739 +3 711 1254 1739 +3 1269 632 1356 +3 1770 974 2113 +3 843 1471 1501 +3 1216 772 1423 +3 868 1216 1423 +3 1238 622 1381 +3 1733 907 1805 +3 591 1114 1956 +3 1513 821 1635 +3 996 1513 1635 +3 1138 52 1765 +3 681 1115 1713 +3 1130 692 1964 +3 1135 798 1955 +3 87 1144 1730 +3 1199 593 1907 +3 734 1165 2095 +3 1165 838 2096 +3 1256 742 1677 +3 1259 621 1595 +3 921 1804 1930 +3 883 1273 1961 +3 1378 790 1729 +3 976 1523 1591 +3 1523 670 1591 +3 1653 1029 2071 +3 169 168 1396 +3 1243 872 1458 +3 761 1195 1609 +3 1195 833 1609 +3 866 1279 1799 +3 1537 580 1878 +3 816 1121 1597 +3 905 1594 1670 +3 1144 796 1941 +3 1368 1583 1951 +3 735 1511 1879 +3 1151 154 1773 +3 1296 649 1775 +3 921 1296 1775 +3 1432 847 1590 +3 1140 592 1635 +3 821 1140 1635 +3 620 1130 1567 +3 141 140 1383 +3 1364 725 1471 +3 1190 783 1967 +3 1177 776 2139 +3 48 47 1344 +3 843 1287 1364 +3 1115 1516 1901 +3 1516 612 1901 +3 1128 587 1583 +3 138 137 1361 +3 1338 774 1339 +3 865 1338 1339 +3 896 1244 1495 +3 603 1129 1589 +3 741 1328 1391 +3 1328 951 1391 +3 795 1246 1410 +3 1246 577 1410 +3 1267 70 1792 +3 744 1144 1941 +3 598 1192 1925 +3 1430 770 1995 +3 1084 1430 1995 +3 798 1151 1955 +3 1121 941 1958 +3 1646 877 1840 +3 1885 14 1923 +3 32 1886 1922 +3 1071 1614 1973 +3 620 1137 1563 +3 1145 844 1537 +3 1496 820 1530 +3 648 1201 1506 +3 1201 808 1506 +3 799 1776 1836 +3 735 1125 1785 +3 1289 782 1626 +3 1162 604 2027 +3 1262 942 1917 +3 671 1262 1917 +3 742 1296 1677 +3 69 68 1460 +3 1187 1348 1714 +3 1132 600 1818 +3 1414 108 1854 +3 1079 1370 2107 +3 1370 595 2107 +3 888 1726 1926 +3 1151 747 1955 +3 790 1234 1445 +3 654 1174 1486 +3 688 1128 1816 +3 798 1429 1887 +3 907 1260 1805 +3 1260 568 1805 +3 908 1517 1899 +3 876 1416 1679 +3 1011 1142 1895 +3 1142 134 1895 +3 764 1324 1695 +3 1325 764 1695 +3 1133 22 1617 +3 872 1243 1731 +3 772 1229 1423 +3 1281 1026 1785 +3 794 1181 2045 +3 996 1134 1983 +3 854 1210 1515 +3 720 1447 1972 +3 1310 803 1397 +3 635 1310 1397 +3 787 1306 1517 +3 1149 714 1790 +3 1182 888 1926 +3 629 1168 1616 +3 781 1835 2090 +3 1671 579 1695 +3 1212 116 1457 +3 1220 743 1442 +3 843 1364 1471 +3 1717 1133 2025 +3 710 1717 2025 +3 25 26 1676 +3 1662 894 1694 +3 589 1181 1657 +3 1776 1099 1836 +3 716 1167 1526 +3 1385 778 1542 +3 1397 803 1403 +3 576 1136 1700 +3 53 1138 1673 +3 901 1411 1909 +3 1496 1530 2097 +3 807 1159 1939 +3 689 1272 1474 +3 1272 815 1474 +3 719 1138 1942 +3 1440 729 1872 +3 1056 1596 2036 +3 1204 980 1561 +3 1332 574 2118 +3 1143 770 1822 +3 1159 618 1939 +3 1031 1712 1917 +3 1233 780 1465 +3 1508 611 1835 +3 1070 1508 1835 +3 1312 949 2013 +3 1146 715 1645 +3 1322 637 1470 +3 865 1139 1740 +3 1239 102 1618 +3 1326 761 1373 +3 939 1375 1530 +3 1375 566 1530 +3 1467 682 1912 +3 647 1555 1883 +3 1060 1986 2023 +3 1338 1214 2133 +3 1144 87 1947 +3 1625 947 1977 +3 837 1419 1680 +3 777 1176 2047 +3 1176 922 2047 +3 858 1153 1620 +3 120 1156 1665 +3 715 1146 1791 +3 1146 852 1791 +3 1217 1119 2022 +3 1189 589 1657 +3 1153 756 1875 +3 154 1151 1887 +3 674 1402 1960 +3 28 1171 1551 +3 1435 858 1543 +3 1153 580 1631 +3 618 1163 1939 +3 1423 632 1829 +3 1664 848 2070 +3 747 1541 1955 +3 1541 1135 1955 +3 788 1240 1582 +3 1528 934 1578 +3 686 1147 1699 +3 932 1231 1988 +3 832 1572 1644 +3 1224 925 1981 +3 1468 999 2061 +3 1163 807 1939 +3 1192 598 2157 +3 951 1192 2157 +3 1234 633 1445 +3 1211 143 1689 +3 862 1211 1689 +3 111 110 1382 +3 851 1149 1790 +3 782 1350 1626 +3 1039 1391 2148 +3 799 1180 1776 +3 1396 929 1767 +3 694 1148 1753 +3 1316 1820 1829 +3 876 1679 1843 +3 822 1397 1403 +3 1181 700 2045 +3 1156 908 1665 +3 572 1167 1585 +3 825 1392 1459 +3 1179 713 1556 +3 1197 173 2053 +3 1201 701 1534 +3 808 1201 1534 +3 70 69 1792 +3 825 1334 1526 +3 1482 733 2048 +3 970 1682 1777 +3 606 1160 2123 +3 1562 975 1586 +3 652 1562 1586 +3 67 66 1372 +3 610 1179 2080 +3 1454 634 1590 +3 56 1245 1931 +3 893 1172 1972 +3 1155 638 1759 +3 840 1155 1759 +3 1613 857 2031 +3 564 1677 1930 +3 144 1211 1760 +3 1599 949 2014 +3 1186 823 1636 +3 628 1186 1636 +3 1543 858 1620 +3 1245 930 1931 +3 1225 705 1905 +3 1676 823 1755 +3 831 1388 1668 +3 862 1161 1847 +3 803 1346 1403 +3 1158 751 1725 +3 706 1633 2138 +3 816 1218 1549 +3 1218 65 1549 +3 990 1168 2060 +3 776 1340 1496 +3 1316 740 1820 +3 1093 1676 1755 +3 1343 601 1575 +3 870 1343 1575 +3 1491 826 2123 +3 1160 1491 2123 +3 145 144 1760 +3 752 1343 1576 +3 1343 870 1576 +3 791 1901 2084 +3 579 1325 1695 +3 1162 732 1761 +3 828 1574 1782 +3 1358 145 1760 +3 1473 591 2142 +3 1184 901 1999 +3 696 1184 1999 +3 962 1763 2124 +3 1167 572 2114 +3 904 1225 1905 +3 1170 18 1641 +3 1306 787 1426 +3 1086 1492 2159 +3 911 1535 1826 +3 830 1522 2143 +3 1370 894 1662 +3 1164 88 1730 +3 813 1209 1514 +3 570 1165 1723 +3 740 1294 2089 +3 1168 629 1685 +3 599 1225 1906 +3 1225 904 1906 +3 857 1546 2031 +3 1122 1241 1962 +3 1633 1159 2138 +3 664 1528 1578 +3 771 1333 1479 +3 777 1167 1796 +3 655 1194 2057 +3 1847 1161 2091 +3 682 1467 1877 +3 1467 1036 1877 +3 594 1198 2119 +3 1198 718 2120 +3 863 1756 1808 +3 654 1363 1543 +3 1346 578 1403 +3 1182 890 1968 +3 700 1182 1968 +3 691 1194 1893 +3 1194 879 1893 +3 849 1439 1548 +3 1171 851 1790 +3 714 1171 1790 +3 52 51 1765 +3 852 1170 1791 +3 845 1272 1473 +3 708 1847 2091 +3 871 1637 2088 +3 888 1182 1638 +3 1171 714 2044 +3 1181 794 1657 +3 756 1174 1875 +3 1835 1113 2090 +3 1446 955 2002 +3 1324 650 1959 +3 48 1344 2160 +3 1453 572 1957 +3 1051 1453 1957 +3 595 1370 1662 +3 602 1173 1807 +3 644 1485 1639 +3 1194 918 2057 +3 1323 998 2015 +3 918 1503 2057 +3 1448 869 1684 +3 153 1175 1773 +3 1176 616 1838 +3 1093 1755 1945 +3 1399 660 1781 +3 609 1177 1857 +3 1290 170 1767 +3 138 1361 2111 +3 1085 1217 2022 +3 961 1704 2025 +3 927 1362 1902 +3 1581 744 1941 +3 1129 1581 1941 +3 627 1202 2135 +3 1372 972 2087 +3 1284 739 1975 +3 941 1284 1975 +3 1239 1618 1820 +3 1186 628 2009 +3 26 1557 1676 +3 1365 875 1758 +3 798 1249 1746 +3 14 15 1923 +3 31 32 1922 +3 171 1290 1862 +3 832 1883 1907 +3 1303 861 1452 +3 569 1539 1993 +3 1572 946 1644 +3 122 1292 1672 +3 942 1262 1658 +3 176 175 1504 +3 1284 61 1502 +3 1252 886 1819 +3 677 1252 1819 +3 1263 754 1483 +3 958 1751 2000 +3 22 23 1617 +3 1186 690 1755 +3 751 1287 1725 +3 734 1191 2001 +3 1191 899 2001 +3 1799 1279 2100 +3 801 1360 1649 +3 653 1278 2052 +3 613 1350 2041 +3 1755 690 1945 +3 1041 1761 2146 +3 589 1189 1668 +3 970 1313 1682 +3 58 1190 1967 +3 1444 726 1863 +3 1721 891 1914 +3 1253 700 1968 +3 1497 979 2021 +3 924 1386 1485 +3 1386 813 1485 +3 173 1197 1698 +3 1072 1441 2082 +3 1344 1018 2160 +3 37 1301 1824 +3 1402 864 1409 +3 932 1318 1834 +3 1781 660 2088 +3 77 76 1427 +3 1441 599 2082 +3 718 1227 1540 +3 107 1333 1854 +3 958 1556 1751 +3 823 1186 1755 +3 1037 1507 1711 +3 792 1402 1409 +3 1211 806 1760 +3 1193 889 1969 +3 1350 928 1626 +3 1524 1183 1966 +3 1448 837 1489 +3 869 1448 1489 +3 1227 808 1540 +3 657 1326 1933 +3 1326 943 1933 +3 754 1285 1483 +3 1188 893 1786 +3 942 1658 1696 +3 614 1207 2126 +3 1210 583 1602 +3 641 1748 2127 +3 779 1472 1642 +3 1472 937 1642 +3 1124 1253 1952 +3 937 1335 1642 +3 1306 822 1512 +3 645 1306 1512 +3 46 45 2026 +3 23 24 1570 +3 1209 813 1688 +3 1492 626 2159 +3 1328 741 1970 +3 977 1444 1863 +3 770 1430 1944 +3 968 1280 2119 +3 1280 594 2119 +3 1285 815 1483 +3 54 53 1673 +3 1399 801 1649 +3 973 1731 1889 +3 104 103 1619 +3 875 1640 1758 +3 1203 628 1636 +3 108 107 1854 +3 1094 1348 1800 +3 1197 910 1698 +3 1596 680 2036 +3 948 1400 1582 +3 972 1372 1927 +3 175 1413 1504 +3 1305 794 2045 +3 1132 1940 1989 +3 1236 626 1558 +3 811 1236 1558 +3 1901 1122 2084 +3 1214 1110 2133 +3 1340 820 1496 +3 650 1200 1959 +3 1574 969 1782 +3 1412 605 2068 +3 1361 994 2111 +3 1308 925 1827 +3 55 54 1653 +3 45 1386 2026 +3 1307 775 1476 +3 585 1553 1752 +3 1553 1005 1752 +3 1264 755 1521 +3 729 1440 2154 +3 604 1196 1914 +3 963 1197 2053 +3 1201 648 1937 +3 808 1282 1506 +3 769 1404 1983 +3 1404 996 1983 +3 1259 1595 1856 +3 880 1333 1709 +3 1333 771 1709 +3 971 1215 1633 +3 641 1425 1538 +3 705 1225 1711 +3 1358 806 2050 +3 1648 931 1919 +3 618 1215 2113 +3 827 1500 1623 +3 1277 802 1845 +3 116 115 1457 +3 1278 795 2052 +3 806 1387 1667 +3 575 1247 1547 +3 729 1214 2103 +3 1382 110 2058 +3 977 1367 1444 +3 783 1415 1967 +3 925 1308 2033 +3 1571 1044 1797 +3 867 1571 1797 +3 955 1446 1783 +3 1446 613 1783 +3 1508 1188 1786 +3 79 78 1461 +3 1980 1051 2099 +3 1222 739 1869 +3 1734 965 2117 +3 161 160 1456 +3 966 1436 1928 +3 1424 814 1425 +3 838 1424 1425 +3 1224 1009 1979 +3 94 1224 1979 +3 898 1289 1953 +3 163 162 1464 +3 975 1562 1799 +3 123 122 1672 +3 685 1546 2155 +3 1332 784 1769 +3 44 1209 1688 +3 1148 1954 2073 +3 605 1412 1737 +3 1336 787 1798 +3 1453 825 2114 +3 1075 1474 1850 +3 949 1312 1705 +3 1400 788 1582 +3 805 1406 2028 +3 1240 615 1582 +3 47 46 1566 +3 36 35 1810 +3 1192 1679 1999 +3 1679 696 1999 +3 1213 678 2051 +3 909 1213 2051 +3 765 1228 1832 +3 919 1354 1719 +3 618 1355 1710 +3 1225 840 1711 +3 1280 935 2011 +3 1106 1208 1994 +3 1205 743 1742 +3 45 44 1688 +3 594 1280 2011 +3 982 1203 2152 +3 726 1444 2093 +3 1277 590 1542 +3 1443 841 1475 +3 988 1382 2058 +3 1203 714 1784 +3 806 1407 2050 +3 1668 1388 2006 +3 1300 813 1514 +3 626 1204 2159 +3 883 1232 1611 +3 61 60 1502 +3 749 1207 1844 +3 1095 1981 2033 +3 1231 147 1978 +3 1008 1231 1978 +3 906 1702 2101 +3 1315 796 1831 +3 1345 761 2092 +3 965 1625 2132 +3 1451 1060 2023 +3 112 111 1643 +3 598 1391 2157 +3 39 1275 1601 +3 886 1252 1859 +3 1958 941 1975 +3 998 1412 2068 +3 563 1208 1929 +3 1940 709 1989 +3 657 1300 1514 +3 1216 100 2024 +3 1207 749 1900 +3 1852 826 1904 +3 913 1667 1848 +3 103 1239 1619 +3 860 1207 1900 +3 1228 639 2153 +3 19 20 1774 +3 829 1560 1630 +3 1560 957 1630 +3 641 1538 1748 +3 1237 863 1808 +3 717 1237 1808 +3 1572 832 1907 +3 1306 645 1517 +3 825 1526 2114 +3 1444 1053 2093 +3 680 1428 2036 +3 51 1593 1765 +3 891 1249 1603 +3 1392 819 1459 +3 627 1219 1812 +3 1283 1491 2054 +3 1405 666 1788 +3 1347 940 2038 +3 1386 45 1688 +3 1682 672 1777 +3 1366 826 1491 +3 642 1366 1491 +3 742 1221 2081 +3 1307 631 1548 +3 1889 640 1976 +3 627 1226 1984 +3 1791 1170 2079 +3 1223 610 1780 +3 1362 927 1525 +3 675 1634 1660 +3 1634 989 1660 +3 1317 641 1515 +3 1702 1038 2101 +3 1024 1264 1645 +3 1268 681 1801 +3 873 1268 1801 +3 1556 713 1751 +3 165 164 1478 +3 838 1317 1600 +3 1317 749 1600 +3 596 1295 1779 +3 1292 122 2098 +3 67 1372 2087 +3 710 1226 1717 +3 1475 841 1498 +3 1342 578 1768 +3 1652 847 2117 +3 1226 834 1717 +3 1315 915 1589 +3 988 1414 1745 +3 126 125 1892 +3 1013 1256 1795 +3 1221 1610 2081 +3 1008 1885 1923 +3 1886 1009 1922 +3 1405 1027 1738 +3 666 1405 1738 +3 917 1399 1649 +3 1226 627 1812 +3 1348 753 1800 +3 173 172 2053 +3 920 1324 1959 +3 105 104 1579 +3 976 1591 1991 +3 1352 789 1794 +3 817 1261 1752 +3 840 1225 2063 +3 780 1335 1954 +3 1335 937 1954 +3 737 1267 1797 +3 1267 867 1797 +3 1275 833 1601 +3 1225 599 2063 +3 995 1573 1747 +3 1573 639 1747 +3 1412 898 1737 +3 1245 55 1653 +3 1220 616 1811 +3 715 1791 2079 +3 1239 740 2089 +3 592 1237 1680 +3 1493 942 1696 +3 878 1493 1696 +3 1244 567 1658 +3 1824 1301 2038 +3 59 58 1967 +3 848 1590 2070 +3 926 1440 1872 +3 154 153 1773 +3 739 1271 1869 +3 739 1222 1975 +3 88 87 1730 +3 1453 1051 1980 +3 815 1285 1850 +3 1349 953 1753 +3 902 1818 1918 +3 1254 567 2005 +3 814 1424 1908 +3 69 1460 1792 +3 1227 718 1795 +3 834 1226 1812 +3 1511 603 1589 +3 915 1511 1589 +3 32 0 1886 +3 146 1 1885 +3 1 14 1885 +3 0 95 1886 +3 1986 950 2023 +3 1407 913 1913 +3 1954 937 2073 +3 1519 774 2133 +3 1110 1519 2133 +3 776 1496 2139 +3 1496 1102 2139 +3 861 1303 1735 +3 1303 581 1735 +3 1588 1157 2115 +3 950 1588 2115 +3 1428 986 2036 +3 1637 994 2088 +3 747 1299 2020 +3 1288 765 1832 +3 1544 834 1774 +3 1025 1263 1784 +3 774 1338 2133 +3 1550 993 1718 +3 1394 737 2110 +3 1377 939 2153 +3 1435 649 1531 +3 858 1435 1531 +3 1232 883 2083 +3 1384 985 1613 +3 1255 836 1685 +3 629 1255 1685 +3 1087 1233 2086 +3 1403 578 1778 +3 708 1230 1847 +3 1230 862 1847 +3 1300 657 1666 +3 844 1300 1666 +3 649 1296 1610 +3 81 80 1509 +3 1279 866 1654 +3 167 1279 1654 +3 887 1498 1545 +3 1498 841 1545 +3 1527 668 1722 +3 973 1527 1722 +3 859 1764 1779 +3 846 1311 1647 +3 1311 74 1647 +3 1266 857 1833 +3 1718 993 2142 +3 890 1253 1968 +3 1253 579 1952 +3 1290 1767 1970 +3 634 1242 1948 +3 804 1552 1553 +3 1552 1005 1553 +3 1289 661 1953 +3 1001 1669 1674 +3 1669 864 1674 +3 717 1238 1961 +3 1238 883 1961 +3 1892 983 1985 +3 1331 846 2066 +3 661 1289 1626 +3 1436 773 1928 +3 1071 1721 1897 +3 920 1671 1695 +3 1238 717 1808 +3 835 1258 1703 +3 1710 805 2028 +3 1578 839 2049 +3 92 1308 1827 +3 568 1260 1690 +3 944 1499 2112 +3 1234 818 1826 +3 1237 717 2131 +3 1467 814 1908 +3 1415 59 1967 +3 1030 1836 2100 +3 740 1239 1820 +3 77 1427 2077 +3 1427 76 2043 +3 2075 1014 2112 +3 42 1345 1921 +3 1345 933 1921 +3 1621 677 1867 +3 1066 1621 1867 +3 1249 656 1746 +3 874 1660 1878 +3 1255 719 1942 +3 786 1232 2083 +3 1258 565 1703 +3 740 1316 1683 +3 1316 855 1683 +3 1658 567 1696 +3 1242 634 1890 +3 1248 738 2010 +3 1235 564 1930 +3 787 1336 1789 +3 1336 881 1789 +3 1351 758 1684 +3 869 1351 1684 +3 846 1362 1525 +3 1287 843 1725 +3 1534 968 1540 +3 808 1534 1540 +3 1276 768 1691 +3 127 126 1532 +3 1618 868 1820 +3 1295 859 1779 +3 832 1443 1475 +3 27 28 1551 +3 1314 136 1655 +3 1242 730 1873 +3 1318 149 1834 +3 656 1249 1973 +3 1249 891 1973 +3 1464 162 2109 +3 859 1242 1890 +3 1308 750 2033 +3 1378 1261 1971 +3 99 98 1913 +3 1623 1500 2107 +3 1372 788 1927 +3 1275 940 1697 +3 947 1385 1542 +3 1393 643 2055 +3 1748 1040 2127 +3 1269 778 1763 +3 122 121 2098 +3 1765 836 1942 +3 1468 624 1855 +3 1271 739 1719 +3 1461 78 2077 +3 1535 911 1576 +3 870 1535 1576 +3 20 21 1544 +3 1401 1023 1709 +3 1244 896 2005 +3 567 1244 2005 +3 1413 810 1504 +3 1261 585 1752 +3 772 1369 1848 +3 1369 913 1848 +3 1047 1464 2109 +3 1484 874 1878 +3 884 1276 1929 +3 1276 563 1929 +3 1300 844 1639 +3 65 64 1549 +3 1032 1461 2077 +3 1244 759 1990 +3 1344 47 1566 +3 1138 1765 1942 +3 158 157 1935 +3 1369 99 1913 +3 1355 974 1564 +3 1802 1057 1919 +3 996 1404 1513 +3 1404 644 1513 +3 1419 837 1616 +3 40 39 1601 +3 1363 907 1733 +3 1058 1363 1733 +3 18 19 1641 +3 645 1248 1899 +3 1068 1477 2155 +3 974 1355 2113 +3 1355 618 2113 +3 1395 831 1522 +3 731 1250 2061 +3 1266 1068 2155 +3 926 1265 2149 +3 161 1456 2109 +3 975 1359 1586 +3 1359 876 1586 +3 681 1431 2046 +3 874 1484 1531 +3 1484 858 1531 +3 639 1452 1747 +3 1283 900 2035 +3 746 1347 2038 +3 1270 596 1779 +3 867 1267 1792 +3 1296 921 1677 +3 877 1310 1840 +3 1310 635 1840 +3 1563 812 1985 +3 1294 740 1683 +3 1302 1012 1690 +3 754 1309 1852 +3 1309 606 2123 +3 1339 774 1592 +3 1614 1071 1915 +3 882 1614 1915 +3 1347 1038 1702 +3 1477 685 2155 +3 1265 597 2149 +3 1909 1150 1925 +3 134 133 1895 +3 896 1254 2005 +3 1116 1737 1953 +3 763 1251 1916 +3 1254 711 2002 +3 647 1475 1498 +3 719 1255 2015 +3 1077 1691 1894 +3 1384 767 2140 +3 985 1384 2140 +3 910 1259 1856 +3 129 1266 1833 +3 853 1314 1655 +3 936 1694 1707 +3 666 1615 1788 +3 836 1255 1942 +3 1077 1319 1691 +3 1292 908 2010 +3 738 1292 2010 +3 1259 910 1888 +3 1536 934 1650 +3 587 1536 1650 +3 866 1396 1654 +3 1396 168 1654 +3 1050 1852 1904 +3 1404 2039 2145 +3 582 1338 1740 +3 1338 865 1740 +3 806 1358 1760 +3 1981 925 2033 +3 1737 898 1953 +3 1411 777 1909 +3 1261 731 1971 +3 769 1344 2039 +3 590 1277 1845 +3 84 83 1896 +3 1458 872 1749 +3 1271 817 1869 +3 1464 1049 2141 +3 163 1464 2141 +3 946 1739 1787 +3 1313 895 1682 +3 826 1366 1904 +3 848 1664 1728 +3 1404 769 2039 +3 1478 164 2141 +3 1686 879 1736 +3 1016 1686 1736 +3 1311 846 1687 +3 136 135 1655 +3 819 1392 1816 +3 165 1478 2067 +3 1480 1084 1547 +3 915 1503 1879 +3 1503 1081 1879 +3 1443 832 1644 +3 1691 768 1894 +3 1666 1080 1982 +3 1279 1030 2100 +3 16 17 1606 +3 29 30 1605 +3 1731 640 1889 +3 608 1587 2037 +3 1448 629 1616 +3 613 1446 1681 +3 1446 889 1681 +3 1396 866 1612 +3 929 1396 1612 +3 672 1455 1777 +3 1273 717 1961 +3 994 1361 1781 +3 1361 801 1781 +3 1331 674 1687 +3 846 1331 1687 +3 793 1480 1547 +3 1627 978 1724 +3 873 1627 1724 +3 960 1482 2048 +3 773 1278 1928 +3 1183 1805 1966 +3 1805 568 1966 +3 60 59 1920 +3 901 1909 1925 +3 1293 970 1777 +3 121 120 1665 +3 1425 814 1538 +3 1455 672 1924 +3 967 1455 1924 +3 102 101 1618 +3 1705 1116 1953 +3 661 1705 1953 +3 1555 884 1743 +3 956 1555 1743 +3 1445 633 1987 +3 758 1323 1684 +3 739 1284 2128 +3 750 1283 2054 +3 1392 825 1980 +3 1820 868 1829 +3 1285 574 1850 +3 642 1283 2035 +3 852 1371 1874 +3 820 1288 1832 +3 1379 851 1876 +3 1871 1045 2042 +3 1511 915 1879 +3 881 1336 1762 +3 1336 118 1762 +3 174 173 1698 +3 1585 777 2047 +3 895 1313 1948 +3 1313 634 1948 +3 828 1435 1543 +3 1324 920 1695 +3 1500 827 1964 +3 672 1524 1924 +3 1524 1003 1924 +3 1409 864 1669 +3 655 1315 1831 +3 880 1414 1854 +3 132 131 1706 +3 902 1573 1940 +3 1421 917 2030 +3 1442 800 1838 +3 844 1666 1982 +3 642 1286 1898 +3 1362 846 1647 +3 73 1362 1647 +3 908 1292 2098 +3 1383 871 2091 +3 155 154 1887 +3 582 1409 1669 +3 1286 642 2035 +3 900 1286 2035 +3 130 129 1833 +3 631 1466 1548 +3 1014 1741 2112 +3 813 1386 1688 +3 636 1384 1613 +3 1301 36 1810 +3 839 1337 1744 +3 578 1545 1768 +3 74 73 1647 +3 1594 600 1996 +3 1069 1594 1996 +3 830 1390 1861 +3 168 167 1654 +3 741 1290 1970 +3 1395 830 1861 +3 1579 945 1821 +3 981 1579 1821 +3 898 1412 1815 +3 1412 758 1815 +3 100 99 2024 +3 580 1537 1982 +3 1360 625 1649 +3 72 71 1902 +3 1380 132 1706 +3 1440 597 1950 +3 953 1440 1950 +3 1538 904 1748 +3 1492 1063 1558 +3 654 1543 1620 +3 1626 928 2014 +3 586 1293 2021 +3 827 1567 1964 +3 810 1413 1856 +3 1413 910 1856 +3 931 1802 1919 +3 571 1298 1938 +3 1296 742 2081 +3 1435 828 1782 +3 1062 1754 1809 +3 1754 865 1809 +3 1664 962 1728 +3 666 1529 1814 +3 1529 964 1814 +3 848 1432 1590 +3 933 1345 2092 +3 1297 1002 2041 +3 1495 1244 1990 +3 59 1415 1920 +3 1304 912 2069 +3 757 1304 2069 +3 1466 849 1548 +3 1421 1057 1802 +3 111 1382 1643 +3 1742 885 1828 +3 657 1514 1998 +3 1678 995 1747 +3 861 1678 1747 +3 643 1299 2055 +3 1299 903 2055 +3 99 1369 2024 +3 34 33 1881 +3 1309 826 1852 +3 658 1347 1702 +3 1376 830 2143 +3 632 1316 1829 +3 87 86 1947 +3 1568 948 1663 +3 1761 732 2146 +3 143 142 1689 +3 746 1301 2078 +3 825 1453 1980 +3 887 1346 1716 +3 1301 746 2038 +3 934 1536 1578 +3 1148 1465 1954 +3 1330 873 1801 +3 1348 607 1714 +3 912 1304 1976 +3 1631 580 1982 +3 1630 957 1693 +3 588 1630 1693 +3 1106 1307 2125 +3 888 1638 1864 +3 1510 957 1560 +3 723 1510 1560 +3 1420 850 1656 +3 1391 951 2157 +3 1477 812 1563 +3 1137 1477 1563 +3 936 1512 1778 +3 1512 822 1778 +3 1355 805 1710 +3 1161 1383 2091 +3 1322 772 1848 +3 1387 637 1667 +3 1098 1342 1768 +3 1564 974 1858 +3 984 1353 1997 +3 1353 124 1997 +3 809 1455 1587 +3 849 1466 1708 +3 826 1309 2123 +3 789 1408 1851 +3 1339 638 1809 +3 865 1339 1809 +3 762 1428 1646 +3 1428 1046 1646 +3 71 1394 1902 +3 803 1310 2032 +3 1517 645 1899 +3 1320 879 1896 +3 810 1595 1596 +3 1595 1108 1596 +3 1313 970 2070 +3 626 1492 1558 +3 879 1320 1893 +3 83 1320 1896 +3 97 96 2050 +3 563 1319 1934 +3 611 1508 1786 +3 774 1519 2034 +3 846 1525 2066 +3 687 1599 1651 +3 1599 928 1651 +3 761 1326 2092 +3 1512 936 1707 +3 1432 848 1728 +3 847 1432 1734 +3 873 1330 1935 +3 96 1358 2050 +3 667 1564 1858 +3 837 1448 1616 +3 1062 1591 1754 +3 1591 670 1754 +3 1333 880 1854 +3 923 1857 2004 +3 118 117 1762 +3 678 1422 2051 +3 1178 1806 2037 +3 1806 608 2037 +3 658 1554 1697 +3 757 1377 1918 +3 1377 902 1918 +3 1521 842 1714 +3 170 169 1767 +3 1474 815 1850 +3 1771 750 2054 +3 1160 1771 2054 +3 611 1447 2064 +3 1447 971 2064 +3 1523 976 1891 +3 832 1475 1883 +3 793 1420 1656 +3 1565 892 1671 +3 920 1565 1671 +3 1562 652 1612 +3 1327 757 1918 +3 1633 706 2065 +3 737 1321 2110 +3 1036 1467 1908 +3 1321 651 2156 +3 954 1365 1758 +3 585 1378 1729 +3 1694 894 1707 +3 1330 158 1935 +3 1670 973 1889 +3 1439 849 1766 +3 1488 1023 1806 +3 573 1559 1652 +3 1559 1019 1652 +3 635 1341 1840 +3 603 1511 2076 +3 1511 1026 2076 +3 1371 702 1874 +3 707 1499 2104 +3 1499 1020 2104 +3 1326 657 1998 +3 1642 1335 2150 +3 1447 611 1786 +3 893 1447 1786 +3 628 1449 2009 +3 703 1379 1876 +3 1726 888 1864 +3 1052 1726 1864 +3 646 1443 1644 +3 1623 1015 1624 +3 827 1623 1624 +3 771 1401 1709 +3 1592 774 2034 +3 1420 627 1984 +3 1440 953 2154 +3 943 1807 2008 +3 659 1625 1734 +3 1625 965 1734 +3 1598 1099 2126 +3 784 1332 2118 +3 1437 586 1803 +3 1541 747 2020 +3 639 1377 2153 +3 868 1423 1829 +3 663 1505 1821 +3 1505 981 1821 +3 38 37 1824 +3 93 92 1827 +3 679 1598 2018 +3 1038 1588 2101 +3 149 148 1834 +3 688 1980 2099 +3 875 1365 1881 +3 1335 610 2150 +3 883 1381 2083 +3 1583 819 1816 +3 964 1529 1811 +3 708 1628 1648 +3 1628 931 1648 +3 157 1627 1935 +3 1515 641 2127 +3 665 1571 1701 +3 90 89 1860 +3 172 171 1862 +3 1116 1436 1737 +3 1692 684 1910 +3 1055 1692 1910 +3 584 1458 1749 +3 1114 1422 1956 +3 63 62 1868 +3 152 151 1870 +3 994 1781 2088 +3 1414 988 2058 +3 109 1414 2058 +3 1720 766 2071 +3 1117 1720 2071 +3 624 1354 1855 +3 1536 839 1578 +3 1018 1438 2160 +3 1438 49 2160 +3 1392 688 1816 +3 1414 880 1745 +3 784 1366 1830 +3 954 1837 2078 +3 1739 896 1787 +3 938 1580 1615 +3 2040 1228 2153 +3 1036 1908 2085 +3 1003 1524 1966 +3 1431 797 2046 +3 1410 577 1766 +3 895 1524 1682 +3 1524 672 1682 +3 972 1460 2087 +3 1460 68 2087 +3 801 1399 1781 +3 1476 704 2125 +3 1100 1378 1971 +3 1531 649 1610 +3 1052 1490 1726 +3 1490 767 1726 +3 822 1403 1778 +3 106 105 2016 +3 659 1432 1728 +3 1841 1162 2027 +3 916 1841 2027 +3 1432 659 1734 +3 43 42 1921 +3 1452 861 1747 +3 1365 34 1881 +3 1841 916 1866 +3 57 56 1931 +3 1738 1027 1828 +3 885 1738 1828 +3 650 1493 1675 +3 1493 878 1675 +3 1460 972 1701 +3 867 1460 1701 +3 1040 1405 1788 +3 874 1531 1610 +3 1344 1566 2039 +3 648 1506 1661 +3 1436 605 1737 +3 1588 588 2101 +3 1494 987 1640 +3 875 1494 1640 +3 1644 946 1787 +3 114 113 2029 +3 1109 1944 2004 +3 938 1615 1814 +3 914 1581 1974 +3 1172 1891 1993 +3 1891 569 1993 +3 649 1435 1782 +3 897 1871 2042 +3 1883 956 1907 +3 147 146 1978 +3 95 94 1979 +3 927 1394 2110 +3 1366 784 1904 +3 599 1441 2063 +3 1595 810 1856 +3 973 1722 1731 +3 1722 872 1731 +3 939 2040 2153 +3 703 1876 2121 +3 1780 610 2080 +3 124 123 1997 +3 1771 1095 2033 +3 1874 702 2122 +3 1533 818 1994 +3 913 1369 1913 +3 953 1349 2154 +3 139 138 2111 +3 962 1437 1763 +3 76 75 2043 +3 866 1562 1612 +3 1460 867 1792 +3 110 109 2058 +3 1911 1163 2028 +3 1528 664 1716 +3 166 165 2067 +3 1233 1465 2086 +3 889 1446 1969 +3 78 77 2077 +3 1001 1846 1872 +3 68 67 2087 +3 1629 871 2088 +3 871 1628 2091 +3 1640 662 1758 +3 162 161 2109 +3 1426 787 1789 +3 940 1824 2038 +3 1046 1368 1951 +3 164 163 2141 +3 49 48 2160 +3 1969 711 2151 +3 1020 1539 2105 +3 1539 569 2105 +3 1727 1089 2012 +3 687 1727 2012 +3 660 1421 1802 +3 1566 46 2026 +3 625 1395 1861 +3 1447 893 1972 +3 1622 906 1793 +3 805 1355 2130 +3 1408 842 1851 +3 1580 854 1615 +3 1621 1066 1938 +3 691 1911 2028 +3 643 1408 1866 +3 1729 886 1859 +3 1384 636 1926 +3 1819 1065 1867 +3 677 1819 1867 +3 1381 786 2083 +3 693 1417 1842 +3 855 1437 1803 +3 1101 1780 2080 +3 1686 84 1896 +3 1557 823 1676 +3 1622 897 1659 +3 906 1622 1659 +3 1394 927 1902 +3 1575 1035 1916 +3 1402 792 1960 +3 906 1693 1793 +3 2039 924 2145 +3 1783 1002 2072 +3 638 1462 1759 +3 931 1628 1629 +3 1628 871 1629 +3 1494 875 2029 +3 651 1674 2066 +3 1615 666 1814 +3 1375 757 2069 +3 1193 1969 2151 +3 1045 1554 2042 +3 1577 130 1833 +3 767 1380 2140 +3 1944 923 2004 +3 788 1400 1927 +3 652 1586 1843 +3 1080 1933 2008 +3 1756 863 1757 +3 1033 1756 1757 +3 1767 929 1970 +3 930 1389 2116 +3 1389 653 2116 +3 1101 1463 1780 +3 1499 707 2112 +3 947 1542 1963 +3 1386 924 2026 +3 1385 659 2124 +3 1876 1127 2121 +3 1388 1052 2006 +3 1126 1874 2122 +3 688 1392 1980 +3 1004 1962 2158 +3 1962 1241 2158 +3 1094 1800 1988 +3 1800 932 1988 +3 1495 646 1787 +3 896 1495 1787 +3 1415 919 1920 +3 1677 921 1930 +3 1541 916 2027 +3 856 1568 1663 +3 1507 705 1711 +3 917 1390 2030 +3 645 1512 1707 +3 1040 1748 1905 +3 1429 155 1887 +3 857 1577 1833 +3 591 1718 2142 +3 797 1516 2046 +3 887 1716 1943 +3 903 1393 2055 +3 1424 570 1908 +3 1487 785 2023 +3 950 1487 2023 +3 1157 1837 2115 +3 1837 662 2115 +3 634 1454 1890 +3 1406 691 2028 +3 1651 928 1681 +3 1619 1239 2089 +3 1849 1055 1957 +3 1897 584 1915 +3 1545 841 1768 +3 1489 837 2131 +3 1422 909 2051 +3 800 1463 1823 +3 1866 916 2020 +3 1407 97 2050 +3 1422 1007 1956 +3 1529 666 1738 +3 885 1529 1738 +3 644 1404 2145 +3 1003 1880 1924 +3 1724 978 1746 +3 656 1724 1746 +3 993 1398 2142 +3 850 1420 1984 +3 1465 694 2086 +3 935 1417 2011 +3 105 1579 2016 +3 1579 981 2016 +3 914 1830 1898 +3 850 1550 1718 +3 1542 590 1963 +3 1846 926 1872 +3 33 1608 1881 +3 1571 867 1701 +3 824 1418 2136 +3 584 1469 1915 +3 1003 1569 1880 +3 875 1608 2029 +3 1620 1153 1875 +3 1835 611 2064 +3 1113 1835 2064 +3 682 1741 1912 +3 1741 1014 1912 +3 1503 655 2057 +3 1071 1897 1915 +3 971 1633 2065 +3 717 1489 2131 +3 1597 1121 1958 +3 1472 623 2073 +3 1593 836 1765 +3 818 1533 1826 +3 1533 911 1826 +3 1570 1093 1945 +3 86 1450 1947 +3 836 1593 2060 +3 1593 990 2060 +3 1554 658 2042 +3 572 1849 1957 +3 889 1651 1681 +3 20 1544 1774 +3 899 1715 1882 +3 579 1671 1952 +3 1133 1617 2025 +3 1499 1132 1989 +3 1481 1073 1943 +3 664 1481 1943 +3 886 1445 1987 +3 1502 919 2128 +3 1933 943 2008 +3 1551 1171 2044 +3 1660 989 1878 +3 653 1434 2116 +3 919 1502 1920 +3 1502 60 1920 +3 1659 658 1702 +3 937 1472 2073 +3 1134 1518 1983 +3 1469 882 1915 +3 1449 845 2009 +3 1776 614 2126 +3 1099 1776 2126 +3 1307 1476 2125 +3 707 2075 2112 +3 1692 922 1823 +3 580 1484 1878 +3 785 1451 2023 +3 1465 780 1954 +3 906 1659 1702 +3 1001 1674 1846 +3 1629 660 1802 +3 931 1629 1802 +3 1491 1160 2054 +3 1600 749 1844 +3 1603 604 1914 +3 597 1440 2149 +3 1284 1502 2128 +3 679 1799 2100 +3 1479 106 2016 +3 1972 1172 2144 +3 1525 927 2156 +3 1440 926 2149 +3 1562 866 1799 +3 662 1487 2115 +3 1487 950 2115 +3 1203 1636 2152 +3 835 1592 2034 +3 692 1500 1964 +3 1732 938 1814 +3 964 1732 1814 +3 1775 969 1804 +3 921 1775 1804 +3 720 1972 2144 +3 899 1723 2001 +3 1091 1481 2049 +3 1481 664 2049 +3 636 1613 2031 +3 572 1453 2114 +3 792 1508 1960 +3 1803 586 2021 +3 1557 982 2152 +3 823 1557 2152 +3 658 1659 2042 +3 1585 922 1849 +3 572 1585 1849 +3 1526 1167 2114 +3 1615 854 1788 +3 897 1622 1992 +3 1553 585 1859 +3 1908 570 2085 +3 718 1540 2120 +3 1128 1583 1816 +3 1750 1090 2048 +3 668 1527 1882 +3 1527 1064 1882 +3 734 1607 2158 +3 1607 1004 2158 +3 676 1622 1793 +3 1080 1666 1933 +3 1880 967 1924 +3 1520 581 1949 +3 918 1520 1949 +3 1608 875 1881 +3 1736 655 1831 +3 981 1479 2016 +3 1672 984 1997 +3 123 1672 1997 +3 837 1680 2131 +3 1540 968 2120 +3 1532 126 1892 +3 646 1644 1787 +3 1586 876 1843 +3 1132 1818 1940 +3 1588 950 1986 +3 588 1588 1986 +3 1770 952 1858 +3 974 1770 1858 +3 1083 1495 1990 +3 1555 956 1883 +3 1020 1499 1989 +3 1508 1070 1960 +3 1602 860 1900 +3 1692 1055 1849 +3 959 1600 1844 +3 1039 1853 2062 +3 1530 566 2097 +3 1693 957 1793 +3 1583 587 1951 +3 1533 563 1934 +3 661 1626 2014 +3 113 1494 2029 +3 939 1530 2040 +3 1530 820 2040 +3 1569 723 1880 +3 1715 1017 2059 +3 668 1715 2059 +3 1693 906 2101 +3 1775 649 1782 +3 911 1533 1934 +3 1074 1817 1903 +3 1485 644 2145 +3 1518 769 1983 +3 924 1566 2026 +3 1665 908 2098 +3 593 1572 1907 +3 1599 687 2012 +3 949 1599 2012 +3 1102 1496 2097 +3 1204 1561 2159 +3 934 1528 2032 +3 1528 803 2032 +3 924 1485 2145 +3 1627 873 1935 +3 1758 662 1837 +3 954 1758 1837 +3 1817 1074 2108 +3 609 1817 2108 +3 1796 1150 1909 +3 1500 1079 2107 +3 1537 844 1982 +3 922 1585 2047 +3 969 1775 1782 +3 1519 1078 2034 +3 1516 1115 2046 +3 961 1570 1945 +3 1674 651 1846 +3 891 1603 1914 +3 999 1708 2061 +3 1708 731 2061 +3 1567 1130 1964 +3 919 1719 2128 +3 916 1541 2020 +3 1525 651 2066 +3 1052 1864 2006 +3 1864 589 2006 +3 1080 1631 1982 +3 922 1692 1849 +3 1179 1556 2080 +3 1242 1873 1948 +3 1546 1022 2031 +3 854 1515 2127 +3 1016 1736 1831 +3 669 1597 1958 +3 1899 1248 2010 +3 651 1525 2156 +3 982 1551 2044 +3 1109 1822 1944 +3 1608 114 2029 +3 905 1670 1889 +3 1522 699 2143 +3 1996 944 2007 +3 1600 959 2096 +3 838 1600 2096 +3 979 1803 2021 +3 585 1729 1859 +3 1170 1641 2079 +3 1566 924 2039 +3 1614 656 1973 +3 1556 1101 2080 +3 690 1704 1945 +3 1704 961 1945 +3 879 1686 1896 +3 1607 734 2095 +3 959 1607 2095 +3 1715 668 1882 +3 928 1599 2014 +3 1974 603 2076 +3 1103 1974 2076 +3 1598 860 2018 +3 1355 1564 2130 +3 1564 1054 2130 +3 1666 657 1933 +3 664 1578 2049 +3 1622 676 1992 +3 1916 1035 1932 +3 763 1916 1932 +3 1168 1685 2060 +3 986 1884 2036 +3 1884 1056 2036 +3 1069 1996 2007 +3 1040 1788 2127 +3 1788 854 2127 +3 1783 613 2041 +3 1002 1783 2041 +3 1671 892 1952 +3 1112 1642 2150 +3 1617 961 2025 +3 1825 1088 2056 +3 991 1825 2056 +3 589 1668 2006 +3 595 1623 2107 +3 571 1938 2017 +3 1938 1066 2017 +3 1561 1086 2159 +3 947 1963 1977 +3 1963 1057 1977 +3 1022 1839 2031 +3 1839 636 2031 +3 1748 904 1905 +3 1610 1296 2081 +3 1919 1057 1963 +3 590 1919 1963 +3 1716 664 1943 +3 1632 824 2136 +3 1637 139 2111 +3 995 1678 2137 +3 682 1877 2007 +3 1877 1069 2007 +3 1832 1228 2040 +3 1083 1990 2019 +3 1990 759 2019 +3 1061 1965 2000 +3 1965 958 2000 +3 945 1619 2089 +3 944 1741 2007 +3 1678 667 2137 +3 1163 1710 2028 +3 2019 759 2094 +3 1105 2019 2094 +3 660 1629 2088 +3 1628 708 2091 +3 1659 897 2042 +3 777 1796 1909 +3 1817 909 1903 +3 1753 953 2003 +3 146 1885 1978 +3 1885 1008 1978 +3 1009 1886 1979 +3 1886 95 1979 +3 1641 1021 2079 +3 1061 1910 1965 +3 1910 684 1965 +3 994 1637 2111 +3 1862 963 2053 +3 2110 1321 2156 +3 927 2110 2156 +3 711 1739 2151 +3 1022 1632 2136 +3 1741 682 2007 +3 1818 902 1940 +3 121 1665 2098 +3 1685 836 2060 +3 2012 1089 2013 +3 949 2012 2013 +3 573 1652 2117 +3 952 1770 2144 +3 1822 770 1944 +3 694 1753 2003 +3 1636 823 2152 +3 659 1728 2124 +3 745 1865 1991 +3 1865 1082 1991 +3 1326 1998 2092 +3 1380 1706 2140 +3 1301 1810 2078 +3 588 1693 2101 +3 1873 895 1948 +3 733 1750 2048 +3 1680 1237 2131 +3 1819 886 1987 +3 1065 1819 1987 +3 750 1771 2033 +3 748 2106 2129 +3 2106 1118 2129 +3 1719 739 2128 +3 1706 985 2140 +3 1741 944 2112 +3 1728 962 2124 +3 955 1783 2072 +3 953 1950 2003 +3 1950 1090 2003 +3 820 1832 2040 +3 1739 946 2151 +3 1810 954 2078 +3 2022 748 2129 +3 1085 2022 2129 +3 908 1899 2010 +3 1923 1126 2122 +3 1008 1923 2122 +3 1127 1922 2121 +3 1922 1009 2121 +3 1770 720 2144 +3 172 1862 2053 +3 1853 963 2062 +3 2095 1165 2096 +3 959 2095 2096 +3 1001 1872 2103 +3 1872 729 2103 +3 1993 952 2144 +3 1904 784 2118 +3 2074 995 2137 +3 2064 971 2065 +3 1113 2064 2065 +3 1050 1904 2118 +3 1172 1993 2144 +3 1036 2085 2102 +3 2085 1064 2102 +3 1998 933 2092 +3 968 2119 2120 +3 2119 1198 2120 +3 2075 1072 2082 +3 2106 748 2134 +3 1075 2106 2134 +3 2104 1020 2105 +3 1082 2104 2105 +3 1014 2075 2082 +3 1051 2093 2099 +3 2093 1053 2099 +3 1123 2074 2137 +3 2589 2212 2726 +3 160 161 2624 +3 2225 2875 3028 +3 2713 2418 2892 +3 2233 2713 2892 +3 2663 2280 3155 +3 208 2584 2920 +3 2324 2566 2866 +3 2736 2493 3205 +3 2653 2305 2963 +3 3221 176 3382 +3 2870 2213 2948 +3 2496 2870 2948 +3 2740 2302 2853 +3 2207 2587 2737 +3 2780 2528 3155 +3 2280 2780 3155 +3 2764 2330 2888 +3 2466 2764 2888 +3 2599 2261 2958 +3 2732 3194 3375 +3 2305 2653 3661 +3 2561 2255 2831 +3 2168 2898 3368 +3 2985 2178 3006 +3 2626 2317 2745 +3 3133 2663 3155 +3 2611 2170 2759 +3 2367 2748 2868 +3 2546 2261 2882 +3 2599 2958 3077 +3 2521 3091 3185 +3 2463 2836 3191 +3 192 2628 3018 +3 2808 2217 2917 +3 2568 2257 2776 +3 2181 2850 3114 +3 2347 2589 3141 +3 168 2607 3389 +3 2898 2570 3368 +3 2226 2612 3007 +3 2178 2775 3006 +3 148 2571 2931 +3 3164 2351 3265 +3 2605 2333 3286 +3 2660 2285 3667 +3 2285 2661 3667 +3 2266 2577 3100 +3 2576 2265 3099 +3 2560 2201 2895 +3 2259 2598 3699 +3 2491 2604 2879 +3 2889 3251 3486 +3 2587 2318 2814 +3 2414 2714 2715 +3 2714 2291 2715 +3 2427 2693 2912 +3 2693 2246 2912 +3 2646 2334 2841 +3 2998 2502 3441 +3 2451 2895 2923 +3 2685 2292 3056 +3 2942 2458 2974 +3 2247 2736 3205 +3 2536 2949 2978 +3 2949 2385 2978 +3 2808 2917 3313 +3 2295 2954 3429 +3 3251 2542 3486 +3 254 3242 3382 +3 3261 2641 3277 +3 2502 2998 3475 +3 2261 2546 2958 +3 271 2804 3498 +3 2584 2459 3300 +3 2639 2394 2760 +3 2393 2638 2761 +3 2714 2512 3295 +3 2777 2468 3003 +3 2265 2777 3003 +3 2434 2591 3174 +3 2591 2238 3174 +3 2185 2669 3050 +3 2669 2438 3050 +3 2580 2258 2811 +3 2363 2580 2811 +3 2734 2308 3063 +3 162 163 2692 +3 2173 2641 3261 +3 2233 3186 3579 +3 2245 2902 3036 +3 175 176 3221 +3 2631 274 3229 +3 2734 219 3168 +3 2742 2178 2985 +3 167 168 3389 +3 2559 2263 3148 +3 2651 2203 2729 +3 3145 2537 3151 +3 2756 2180 2945 +3 2447 2756 2945 +3 2750 2288 3275 +3 2184 2598 2806 +3 244 3208 3396 +3 2533 2750 3275 +3 2638 257 3021 +3 283 2639 3022 +3 2773 2225 3028 +3 2200 2558 3418 +3 2687 250 3066 +3 2798 2233 3579 +3 2758 2259 3699 +3 2310 2584 2798 +3 2616 2319 2788 +3 2171 2616 2788 +3 2701 2378 2711 +3 2592 2323 2786 +3 2655 2440 3122 +3 3465 2894 3507 +3 2504 3024 3198 +3 2898 2168 2981 +3 2728 2266 2971 +3 2462 2728 2971 +3 2768 2232 3048 +3 2472 2768 3048 +3 2291 2714 3295 +3 2201 2560 3434 +3 2855 2515 3054 +3 2356 2855 3054 +3 2195 2643 3085 +3 3054 2515 3218 +3 2242 2701 2711 +3 2555 166 3389 +3 271 270 2804 +3 2598 2184 3398 +3 2601 2451 3456 +3 2572 2268 3053 +3 2421 2585 3133 +3 2711 2302 3034 +3 2894 2337 3507 +3 220 219 2734 +3 2593 2166 2809 +3 2316 2593 2809 +3 2211 2661 2807 +3 196 3019 3239 +3 2686 2350 2940 +3 2396 2630 3100 +3 2629 2395 3099 +3 2367 2868 2979 +3 2909 2186 3272 +3 2708 2589 3553 +3 2286 2708 3553 +3 2574 2909 3272 +3 2584 208 3223 +3 2685 2204 2960 +3 160 2624 2904 +3 2598 2259 3387 +3 2999 2642 3713 +3 2270 2596 3318 +3 2596 2467 3318 +3 2683 3580 3599 +3 2477 2710 3177 +3 2710 2293 3177 +3 2584 2310 2920 +3 2692 163 3299 +3 2554 2389 2976 +3 2444 3145 3151 +3 2428 2805 2844 +3 2805 2325 2844 +3 2389 2554 3025 +3 2740 2853 3160 +3 2604 2491 3415 +3 2683 2301 3580 +3 2239 2655 3122 +3 166 2555 3031 +3 3091 2435 3185 +3 2676 201 3255 +3 2895 2201 2923 +3 3140 2298 3359 +3 2280 2579 2916 +3 2699 177 3197 +3 2630 2396 3146 +3 2197 2660 2846 +3 3063 2308 3585 +3 2315 2565 2886 +3 2163 2601 3025 +3 2601 2389 3025 +3 2184 3156 3175 +3 2313 2747 2908 +3 2302 2740 3034 +3 2638 2328 2761 +3 2329 2639 2760 +3 3208 2551 3396 +3 2595 2340 3728 +3 2650 2365 2996 +3 2263 2559 3080 +3 2320 2595 3452 +3 3203 2552 3464 +3 2566 2324 3262 +3 2562 3061 3568 +3 2558 2200 3043 +3 2335 3181 3443 +3 2813 234 3565 +3 2281 2997 3210 +3 2691 2309 2733 +3 254 253 3242 +3 2255 2561 2934 +3 3133 2585 3378 +3 2268 2572 3233 +3 2997 2552 3210 +3 2257 2568 2962 +3 2800 2321 3115 +3 2802 2492 3090 +3 2266 2630 2971 +3 2630 2382 2971 +3 2491 2879 3259 +3 2298 3140 3297 +3 2617 2269 3342 +3 2476 2617 3342 +3 2579 2280 3033 +3 2797 2174 3057 +3 2963 2305 3090 +3 2759 2170 3144 +3 2757 2177 3288 +3 2537 2757 3288 +3 2574 2326 2878 +3 2470 2818 2979 +3 2818 2367 2979 +3 2521 2649 3091 +3 2939 2685 3056 +3 2611 2759 3316 +3 2640 2250 3137 +3 2618 2345 3432 +3 241 3027 3551 +3 2742 2985 3427 +3 2589 2708 3141 +3 2565 2315 3183 +3 2581 3140 3359 +3 2305 2802 3090 +3 2176 2647 2847 +3 2184 2988 3156 +3 2310 2605 2920 +3 2219 3054 3218 +3 2879 2604 3557 +3 2619 246 3396 +3 2582 2369 2966 +3 2395 2629 3138 +3 2954 2564 3429 +3 2593 2316 3216 +3 2825 2184 3175 +3 2333 2605 3397 +3 3144 2170 3165 +3 2326 2574 3272 +3 2292 2732 3375 +3 2626 2248 3235 +3 2652 2417 2910 +3 2321 3057 3115 +3 242 241 3551 +3 2179 2608 2936 +3 2333 2883 3286 +3 2843 3185 3214 +3 2712 2198 2805 +3 2428 2712 2805 +3 2322 2812 2825 +3 2812 2413 2825 +3 2297 2694 2743 +3 2779 2357 2893 +3 2427 2779 2893 +3 2191 3133 3378 +3 2171 2615 3461 +3 3061 2562 3476 +3 2172 2682 2855 +3 2595 2320 2937 +3 2680 2189 2860 +3 2350 2754 2940 +3 2356 2793 3393 +3 2843 2229 3185 +3 2223 3203 3464 +3 3393 2793 3471 +3 2318 2679 2814 +3 2587 2207 3002 +3 2846 2660 3667 +3 2338 2817 3205 +3 2504 3164 3265 +3 2317 2626 2801 +3 179 2716 3197 +3 2246 2693 3762 +3 2800 2228 3238 +3 3059 2586 3064 +3 2309 2691 3649 +3 2228 3135 3238 +3 2649 3112 3281 +3 2623 2358 2923 +3 2201 2623 2923 +3 2748 2227 2752 +3 2344 2748 2752 +3 2902 2471 3036 +3 2884 3230 3244 +3 2314 2624 3049 +3 2173 2709 3379 +3 2313 2689 2933 +3 2205 2667 3264 +3 2661 2211 2872 +3 2713 2233 3149 +3 2742 2378 2834 +3 2372 2942 2974 +3 3057 2174 3249 +3 2836 2463 3400 +3 2335 2851 3181 +3 2753 2303 3172 +3 2178 2742 2834 +3 2355 2846 3667 +3 2954 2295 3145 +3 2370 2829 2852 +3 2200 2722 3521 +3 2224 2827 2878 +3 203 204 3074 +3 3074 204 3586 +3 2319 2616 3416 +3 2586 2257 2962 +3 2186 2909 2993 +3 2759 2479 3316 +3 2975 2223 3189 +3 2691 3519 3649 +3 191 192 3018 +3 2493 2736 3065 +3 3430 2259 3486 +3 2722 3310 3521 +3 2715 2291 3089 +3 177 178 3197 +3 2571 148 3465 +3 2467 2596 2882 +3 3158 2753 3172 +3 2632 2218 3118 +3 2651 2729 3580 +3 2651 3580 3721 +3 2323 2592 2889 +3 2359 2773 2858 +3 2773 2402 2858 +3 2381 2629 3003 +3 2629 2265 3003 +3 201 202 3255 +3 2250 2640 3547 +3 2235 2648 3424 +3 2299 2695 3736 +3 2696 2299 3736 +3 3024 2392 3198 +3 2796 2633 3632 +3 274 273 3229 +3 3019 2511 3239 +3 2625 2182 2821 +3 250 249 3066 +3 3044 2594 3540 +3 2713 2313 2933 +3 2161 3192 3404 +3 2257 2586 3059 +3 2243 2844 3044 +3 2360 2879 3557 +3 2590 3150 3501 +3 2715 2192 2963 +3 2414 2715 2963 +3 2709 3207 3379 +3 3069 2906 3530 +3 2850 2442 3114 +3 2258 2580 3211 +3 2642 2999 3188 +3 2212 2589 2956 +3 2589 2347 2956 +3 2622 2286 3553 +3 3150 2272 3501 +3 2250 2731 3137 +3 2731 2461 3137 +3 2579 2316 2959 +3 2223 2816 3189 +3 2259 2758 3486 +3 2692 2466 2785 +3 2665 174 3221 +3 2375 3011 3288 +3 252 2673 3242 +3 2601 2163 3073 +3 2175 2754 2772 +3 2754 2350 2772 +3 2884 2453 3230 +3 3112 2407 3281 +3 2285 2660 2897 +3 2391 2620 2865 +3 2459 2584 3223 +3 2577 2266 3154 +3 2238 2591 3356 +3 3246 2355 3327 +3 2226 3007 3213 +3 3038 2450 3170 +3 2588 2275 2943 +3 2362 2999 3713 +3 2988 2338 3205 +3 3194 2486 3375 +3 2633 2796 3657 +3 2369 3059 3064 +3 2265 2576 3219 +3 2325 2796 3632 +3 2326 2610 2876 +3 2610 2268 2876 +3 2707 2216 2838 +3 2847 2647 3630 +3 2594 3044 3363 +3 2324 2609 3262 +3 2275 2588 2927 +3 2605 2310 3397 +3 2617 2476 3388 +3 2205 2613 3020 +3 2613 2376 3020 +3 2879 2196 3259 +3 3140 2554 3297 +3 2241 2695 3013 +3 2647 2176 2823 +3 235 234 2813 +3 2573 3246 3327 +3 2903 2498 3029 +3 2400 2903 3029 +3 2443 2679 3144 +3 2679 2318 3144 +3 2314 2692 2785 +3 2293 2659 3177 +3 218 217 2767 +3 2606 2296 3681 +3 2958 2354 3077 +3 2360 2581 3359 +3 2316 2579 3033 +3 2268 2610 2926 +3 2374 2719 2877 +3 2719 2237 2877 +3 2610 2326 3272 +3 2798 2584 3300 +3 2783 2387 2847 +3 2162 2801 3128 +3 2288 2750 3065 +3 2208 2761 2929 +3 2932 2601 3456 +3 2189 2680 2989 +3 3008 2376 3080 +3 2296 2606 3309 +3 2163 2581 3009 +3 2649 2521 3518 +3 3044 2844 3632 +3 2830 2397 3041 +3 2581 2163 3140 +3 2449 2771 3013 +3 2771 2241 3013 +3 2261 2599 2973 +3 2599 2349 2973 +3 2566 2813 3565 +3 2770 2361 2784 +3 2230 2770 2784 +3 2580 2363 3043 +3 2796 2177 3657 +3 2343 2847 3630 +3 2805 2198 3438 +3 2544 3221 3382 +3 2198 3425 3438 +3 2581 2360 3325 +3 178 179 3197 +3 2369 2582 3059 +3 2750 2448 3065 +3 2329 2760 2947 +3 2340 2832 3728 +3 2389 2601 2932 +3 3264 2667 3490 +3 2311 2836 2909 +3 2836 2464 2909 +3 2624 2314 3573 +3 3203 2445 3481 +3 2640 3137 3524 +3 2536 3167 3172 +3 3128 2801 3746 +3 2479 3108 3316 +3 2873 2450 3038 +3 2318 2587 3002 +3 2431 2664 3422 +3 2661 2872 3667 +3 2806 2598 3387 +3 2596 2270 2970 +3 2166 2593 3209 +3 2326 2703 2878 +3 2909 2464 2993 +3 2623 2268 2926 +3 3112 2649 3518 +3 2323 2889 3486 +3 2213 2755 2814 +3 2848 2339 3319 +3 3623 2845 3671 +3 2692 2314 3049 +3 2679 2213 2814 +3 3319 2339 3408 +3 2559 3008 3080 +3 2591 2434 2989 +3 2436 2621 2900 +3 2632 2303 3737 +3 213 214 2710 +3 2585 2421 3087 +3 2269 3112 3518 +3 2479 2911 3108 +3 2207 2586 3570 +3 2406 2968 2992 +3 2334 2731 3130 +3 2365 2650 3289 +3 2586 2207 3064 +3 2577 2791 3100 +3 2792 2576 3099 +3 2604 2212 3557 +3 3011 2537 3288 +3 2657 2163 3009 +3 2388 2657 3009 +3 2195 3085 3437 +3 2171 3461 3710 +3 2235 2906 3069 +3 2789 2370 2852 +3 2320 3452 3670 +3 2265 2629 3099 +3 2630 2266 3100 +3 3280 2369 3453 +3 2349 2599 3248 +3 2785 2234 3273 +3 2212 2604 3402 +3 2608 2179 3401 +3 2281 2672 3663 +3 2685 2960 3346 +3 2441 2734 3168 +3 2329 2947 3474 +3 2836 2311 3191 +3 2672 2411 3450 +3 2280 2663 3033 +3 2643 2195 2995 +3 2715 3089 3445 +3 2512 2714 3532 +3 2286 2622 3339 +3 3580 2564 3599 +3 2313 2908 3451 +3 2690 2408 2837 +3 2496 2806 3387 +3 2785 3273 3472 +3 3062 2371 3367 +3 2830 3041 3270 +3 2340 2595 3206 +3 2466 2692 3299 +3 3149 2233 3300 +3 2213 2679 2948 +3 2766 2367 2818 +3 2218 2766 2818 +3 2751 2458 2942 +3 2343 2752 2783 +3 2752 2227 2783 +3 2412 2594 3072 +3 2452 2712 3243 +3 2872 2355 3667 +3 2992 2968 3511 +3 2594 2412 3540 +3 2736 2288 3065 +3 2612 2226 3290 +3 2614 2230 2937 +3 2310 2643 3397 +3 2955 2556 3195 +3 2878 2827 3534 +3 284 283 3022 +3 257 256 3021 +3 2937 2320 3722 +3 2784 2361 2787 +3 2340 2784 2787 +3 2341 2634 2913 +3 2634 2194 2913 +3 2754 2407 2940 +3 2358 2623 2926 +3 2614 2937 3722 +3 2744 2364 2835 +3 2174 2744 2835 +3 2460 2898 2981 +3 273 272 3229 +3 2445 2835 3481 +3 272 3000 3229 +3 2264 2955 3195 +3 2609 2324 3588 +3 2210 2691 2880 +3 2260 2703 3705 +3 2416 2861 3051 +3 2769 2334 3130 +3 2345 2869 3432 +3 207 208 2920 +3 2734 2441 3088 +3 2308 2734 3088 +3 2273 2637 2907 +3 2451 2601 3258 +3 3243 2712 3483 +3 2356 2642 3188 +3 2263 2613 3594 +3 2741 2484 3294 +3 2385 2682 2978 +3 2682 2172 2978 +3 2613 2205 3101 +3 2804 2530 3498 +3 2988 2493 3156 +3 3224 2202 3279 +3 2645 2426 2897 +3 2401 2607 3109 +3 2864 2521 3185 +3 2229 2864 3185 +3 2931 2293 3688 +3 2384 2603 3179 +3 2810 2346 2820 +3 2379 2810 2820 +3 2658 2295 3429 +3 2703 3010 3705 +3 3060 2592 3611 +3 2646 2841 3503 +3 2344 2752 3727 +3 2626 3235 3746 +3 2328 2638 3021 +3 2639 2329 3022 +3 2845 2331 3671 +3 277 2889 3602 +3 203 3074 3255 +3 2218 2632 3595 +3 2934 2535 3328 +3 3242 2544 3382 +3 2767 217 3390 +3 2833 2283 3712 +3 2855 2682 3423 +3 2702 2833 3712 +3 2603 2384 3139 +3 2293 2931 3709 +3 2163 2657 3073 +3 2776 2312 3078 +3 2631 2380 3098 +3 2619 2404 3111 +3 2391 2690 2837 +3 246 245 3396 +3 2418 2616 3414 +3 2459 2747 3149 +3 2747 2313 3149 +3 2272 2634 3354 +3 3260 2187 3695 +3 2335 2635 3178 +3 2607 2401 3173 +3 2896 3356 3408 +3 2282 2645 2910 +3 2334 2646 3083 +3 2328 2716 2929 +3 2716 2411 2929 +3 2431 2862 2905 +3 2862 2348 2905 +3 2402 2620 3005 +3 2358 2926 2967 +3 3077 2169 3248 +3 3096 2254 3305 +3 2607 168 3109 +3 2700 2329 3390 +3 2752 2803 3727 +3 2702 2437 2833 +3 2404 2619 3169 +3 2635 2335 3199 +3 2184 2806 2988 +3 2867 2220 2974 +3 2458 2867 2974 +3 2664 2246 2891 +3 2717 2196 2879 +3 2360 2717 2879 +3 2417 2675 3349 +3 2613 2263 3080 +3 2376 2613 3080 +3 2655 2239 3011 +3 2375 2655 3011 +3 2896 2238 3356 +3 2726 2622 3553 +3 2599 3077 3248 +3 2752 2343 2803 +3 2170 2611 3292 +3 2642 2219 3713 +3 2230 2614 3410 +3 155 156 2732 +3 2718 2362 2824 +3 2423 2718 2824 +3 2203 2651 3452 +3 2243 3044 3540 +3 2811 2487 2969 +3 2377 2680 2860 +3 2769 2164 2961 +3 2648 2935 3424 +3 3322 2247 3338 +3 2627 2254 3096 +3 2781 2216 3200 +3 2953 2577 3154 +3 2366 3517 3733 +3 202 203 3255 +3 2394 2639 3331 +3 2638 2393 3330 +3 3167 2422 3172 +3 2634 2341 3354 +3 2671 2275 2927 +3 2415 2671 2927 +3 2321 2707 2838 +3 2311 2827 3191 +3 2827 2503 3191 +3 2303 2632 3118 +3 2622 2169 3016 +3 2345 2618 3042 +3 2169 2622 3248 +3 184 2621 3070 +3 2741 2463 3192 +3 2161 2741 3192 +3 2628 192 3227 +3 2455 3261 3277 +3 2966 2369 3280 +3 2621 3623 3671 +3 2672 2774 3663 +3 2615 2171 3351 +3 174 2665 3116 +3 2641 2173 3379 +3 2616 2418 3416 +3 2939 2366 3733 +3 2273 2674 3131 +3 210 211 2747 +3 2648 2299 2935 +3 2648 2430 2936 +3 280 279 2791 +3 261 260 2792 +3 2620 2391 3419 +3 2846 2704 3698 +3 2197 2846 3698 +3 3127 2578 3708 +3 2616 2171 3120 +3 2381 2797 2838 +3 2797 2321 2838 +3 2269 2617 3112 +3 2620 2402 3564 +3 188 2656 3449 +3 2829 2225 2852 +3 2416 3051 3339 +3 2860 2189 3715 +3 246 2619 3111 +3 2621 2436 3070 +3 2862 2161 3404 +3 2362 2628 2999 +3 2268 2623 3053 +3 2763 2425 3148 +3 2290 2741 3294 +3 2191 2706 3575 +3 2706 2543 3575 +3 2753 2625 3737 +3 2303 2753 3737 +3 2611 3037 3292 +3 2372 2709 2942 +3 2709 2173 2942 +3 2623 2201 3276 +3 164 165 2764 +3 2247 2817 3338 +3 2688 2490 3211 +3 2222 2743 3092 +3 2621 184 3623 +3 2418 2713 3645 +3 2371 2970 3367 +3 2571 3465 3507 +3 2484 2741 3319 +3 3037 2368 3292 +3 2352 2864 3104 +3 2314 2722 3573 +3 2624 161 3049 +3 2227 2748 2881 +3 2748 2367 2881 +3 2722 2200 3418 +3 2627 2342 3017 +3 194 195 2749 +3 2299 2696 3617 +3 2738 2221 2890 +3 2442 2738 2890 +3 2438 2669 3502 +3 2274 2670 3502 +3 2669 2274 3502 +3 2628 2362 3018 +3 2218 2818 3473 +3 2470 2769 3130 +3 2803 2343 3757 +3 2394 2953 3154 +3 2880 2691 3739 +3 2670 2219 3218 +3 2650 2996 3328 +3 253 252 3242 +3 2904 2624 3573 +3 2219 2642 3054 +3 2390 2633 3657 +3 2578 3127 3615 +3 2670 3218 3502 +3 2343 3630 3757 +3 2274 2669 3634 +3 2440 2655 3282 +3 216 2700 3390 +3 3218 2438 3502 +3 2293 2710 3688 +3 2902 2245 3592 +3 2820 2249 2828 +3 2379 2820 2828 +3 2248 2626 3254 +3 3473 2818 3690 +3 2245 3171 3269 +3 2192 2653 2963 +3 2362 2718 3018 +3 2239 2727 3151 +3 2727 2444 3151 +3 2301 2683 3571 +3 2856 2183 3201 +3 2206 2723 3727 +3 2354 2880 3739 +3 2633 2390 3044 +3 2630 2215 3102 +3 2382 2630 3102 +3 2821 2182 2893 +3 2350 2686 3642 +3 2629 2381 3457 +3 2276 2641 3012 +3 2329 2767 3390 +3 2656 188 3093 +3 2626 2745 3254 +3 3055 2375 3187 +3 174 175 3221 +3 2673 252 3123 +3 2340 2787 3128 +3 245 244 3396 +3 2380 2631 3229 +3 2254 2627 3724 +3 2328 2699 3197 +3 3559 2842 3655 +3 2739 224 3301 +3 2735 2504 3198 +3 2182 2625 3142 +3 2342 2627 3096 +3 2695 2241 3608 +3 2256 2654 2986 +3 2294 2662 3042 +3 274 2631 3228 +3 2628 3227 3332 +3 2967 2926 3561 +3 2687 2426 3399 +3 3227 2480 3332 +3 3037 2611 3316 +3 2957 2494 3015 +3 2371 2957 3015 +3 2241 2697 3608 +3 2303 3118 3172 +3 2724 3347 3409 +3 208 209 3223 +3 2550 3224 3279 +3 2215 2630 3146 +3 3199 2335 3443 +3 2271 2655 3055 +3 2655 2375 3055 +3 2210 2762 3519 +3 2762 2553 3519 +3 2664 2891 3422 +3 2336 2904 3573 +3 2775 2178 2859 +3 2411 3129 3450 +3 147 148 2931 +3 3461 2668 3710 +3 277 276 2889 +3 2262 3037 3316 +3 2735 2297 2865 +3 2292 2685 3567 +3 2641 2276 3277 +3 2694 2297 2915 +3 2642 2356 3054 +3 2888 2330 3468 +3 2699 2328 3021 +3 2329 2700 3022 +3 2889 2592 3602 +3 2659 2293 3709 +3 2654 2445 3606 +3 280 2791 3703 +3 2792 260 3702 +3 2826 2492 3190 +3 2361 2826 3190 +3 2211 2861 2872 +3 2861 2416 2872 +3 3297 2554 3407 +3 2242 2711 3034 +3 2194 2634 3614 +3 2821 2632 3737 +3 2634 2272 3150 +3 2272 3354 3544 +3 2403 2859 2885 +3 2780 2280 2916 +3 2299 2648 3323 +3 152 2650 3345 +3 2823 2392 3040 +3 2255 2934 3328 +3 2330 3392 3468 +3 257 2638 3330 +3 2639 283 3331 +3 2249 2820 3226 +3 2637 2273 3131 +3 2488 2856 3201 +3 2681 2364 2972 +3 2208 2681 2972 +3 2274 2842 3559 +3 2306 2725 3062 +3 2284 2652 3245 +3 2716 2328 3197 +3 2483 2887 3094 +3 2887 2428 3094 +3 2653 2192 3708 +3 2700 216 3600 +3 177 2699 3601 +3 2643 2310 3085 +3 2689 2199 2933 +3 2403 2775 2859 +3 2993 3347 3386 +3 2967 2186 2993 +3 2482 2967 2993 +3 3347 2464 3409 +3 2204 2685 2939 +3 2172 2855 3393 +3 2748 2344 2868 +3 2232 2686 2940 +3 2657 2388 3030 +3 2240 2871 3253 +3 3150 2590 3515 +3 3078 2781 3200 +3 2847 2387 3032 +3 2721 2350 3642 +3 2430 2648 3285 +3 2763 3148 3435 +3 2622 2726 3750 +3 2655 2271 3282 +3 2901 236 3287 +3 2773 2359 2852 +3 2803 2206 3727 +3 2482 2993 3386 +3 3580 2301 3721 +3 3061 2395 3568 +3 2747 211 2908 +3 3004 2199 3526 +3 2741 2161 3319 +3 2776 3078 3539 +3 2859 2370 2885 +3 2654 2256 3306 +3 2446 2654 3306 +3 2636 3199 3443 +3 2697 2241 3030 +3 2388 2697 3030 +3 2188 2696 3141 +3 2656 2423 3220 +3 2969 2487 3355 +3 2648 2235 3285 +3 2225 2773 2852 +3 2208 2929 3147 +3 2295 2658 3326 +3 2757 2537 3145 +3 2645 2282 3234 +3 2426 2645 3234 +3 2810 2201 3434 +3 2789 2359 2890 +3 2649 2175 3091 +3 2729 2203 3744 +3 3452 2651 3670 +3 2374 2875 2921 +3 2875 2429 2921 +3 2352 3104 3646 +3 2672 2281 3161 +3 2411 2672 3161 +3 2187 3157 3695 +3 2688 3211 3674 +3 2592 3060 3602 +3 2199 2689 3526 +3 2657 2332 3073 +3 2840 2193 3543 +3 2606 2840 3543 +3 2662 2294 3058 +3 2858 2181 3114 +3 2661 2285 3263 +3 2716 179 3129 +3 2343 2783 2847 +3 2512 3267 3298 +3 2667 2205 3020 +3 2940 2407 3048 +3 2680 2377 3504 +3 2572 3053 3566 +3 2378 2701 3105 +3 2711 2378 3597 +3 2713 2933 3645 +3 2961 2164 3107 +3 2731 2334 3083 +3 2359 2789 2852 +3 2659 3004 3526 +3 2423 2656 3093 +3 2172 3393 3541 +3 2333 2727 3193 +3 2709 2287 3207 +3 2524 3096 3305 +3 2519 2732 3567 +3 2350 2721 3026 +3 2650 152 3289 +3 2576 2952 3219 +3 2698 2353 3119 +3 2786 2323 3560 +3 2175 2649 3281 +3 3313 2373 3355 +3 2970 2371 3015 +3 2819 2559 3148 +3 2840 2606 3681 +3 2686 2232 2980 +3 2691 2733 3739 +3 2547 2737 3620 +3 2470 3130 3237 +3 2708 2188 3141 +3 2218 2949 3118 +3 2669 2185 3421 +3 2654 2446 3249 +3 2367 2766 2881 +3 2698 2202 3224 +3 2445 2654 3247 +3 2378 2829 2834 +3 2779 2227 3726 +3 2652 2284 3215 +3 2417 2652 3215 +3 2332 2657 3344 +3 2691 2210 3519 +3 3216 2316 3533 +3 3052 2278 3262 +3 2609 3052 3262 +3 2882 2261 3103 +3 3044 2390 3363 +3 2875 2374 3028 +3 2512 2808 3267 +3 3118 2536 3172 +3 2705 2353 3136 +3 240 239 2819 +3 2515 2855 3423 +3 2178 2834 2859 +3 2690 2391 3071 +3 2789 2221 2885 +3 2370 2789 2885 +3 2256 3083 3306 +3 3083 2646 3306 +3 2371 2725 2957 +3 2725 2234 2957 +3 2994 2245 3269 +3 2249 3226 3666 +3 2452 2706 2955 +3 2871 2451 2923 +3 2737 2587 3751 +3 2230 2784 3206 +3 2240 3253 3385 +3 2829 2370 2834 +3 2513 3069 3530 +3 2745 2317 3489 +3 2840 2457 3052 +3 2799 2387 2912 +3 2246 2799 2912 +3 2899 2365 3289 +3 2853 2540 3302 +3 213 2710 3307 +3 2351 2719 2938 +3 2660 2197 3589 +3 2373 2945 3355 +3 237 236 2901 +3 2514 3055 3187 +3 2664 2431 3357 +3 3354 2644 3544 +3 2874 2522 3290 +3 2231 2720 2991 +3 2720 2377 2991 +3 2346 2914 3587 +3 3620 2737 3751 +3 2287 2724 3207 +3 2719 2351 3164 +3 2905 2348 3079 +3 162 2692 3049 +3 3181 2539 3443 +3 2681 2281 3210 +3 2175 2778 3091 +3 2778 2435 3091 +3 3226 2346 3587 +3 3196 2516 3333 +3 3137 2461 3675 +3 2490 2688 3487 +3 2678 2287 3304 +3 2886 2193 3376 +3 3392 2637 3448 +3 3013 2695 3358 +3 2373 2770 2928 +3 2770 2230 2928 +3 3137 2563 3524 +3 2352 2782 3523 +3 2766 2218 3595 +3 3177 2659 3526 +3 2763 2235 3069 +3 2425 2763 3069 +3 2726 2212 3402 +3 2816 2223 2900 +3 2246 2664 3482 +3 3302 2540 3738 +3 2467 2882 3103 +3 2226 2874 3290 +3 2896 2339 2964 +3 2600 2860 3715 +3 2791 2577 3703 +3 2576 2792 3702 +3 2439 2666 3152 +3 2745 2506 3254 +3 2287 2678 3386 +3 2710 2477 3307 +3 2793 2356 3188 +3 2756 2447 3001 +3 2290 2680 3504 +3 2221 2789 2890 +3 2227 2881 3726 +3 2210 2674 3159 +3 2674 2401 3159 +3 223 222 3097 +3 2426 2673 3123 +3 2439 2896 2964 +3 2807 2661 3263 +3 3371 2641 3379 +3 2718 2423 3508 +3 2919 2483 3094 +3 2243 2919 3094 +3 2373 2928 2945 +3 2928 2447 2945 +3 2952 2393 3219 +3 2724 2287 3347 +3 2431 2848 2862 +3 2848 2161 2862 +3 2732 2519 3428 +3 2658 3429 3744 +3 2799 2410 3271 +3 169 170 2946 +3 2666 2439 3217 +3 2552 2997 3464 +3 2217 2826 3719 +3 2732 2292 3567 +3 2671 2415 3609 +3 3131 2674 3480 +3 2292 2684 3056 +3 2408 2690 3079 +3 2703 2326 3010 +3 2297 2735 3198 +3 2219 2670 3364 +3 220 2734 3063 +3 2275 2671 3169 +3 2290 2720 3204 +3 2689 2313 3451 +3 2424 2736 3124 +3 2736 2247 3124 +3 2670 2274 3220 +3 3027 2425 3069 +3 2513 3027 3069 +3 2878 2703 3324 +3 2733 2309 3692 +3 2353 2705 3535 +3 2849 2300 3701 +3 2673 2426 3234 +3 2396 3060 3611 +3 2834 2370 2859 +3 2717 2360 3359 +3 2674 2210 3480 +3 3142 2342 3546 +3 2401 2674 3173 +3 2352 3523 3581 +3 2674 2273 3173 +3 2770 2373 2917 +3 2987 2786 3560 +3 2487 2811 3267 +3 2811 2258 3267 +3 2761 2328 2929 +3 2399 2856 3108 +3 2652 2910 3374 +3 2697 2956 3608 +3 2956 2347 3608 +3 2497 2723 2982 +3 2488 2765 3350 +3 2765 2262 3350 +3 2698 2289 3040 +3 3222 2389 3687 +3 2415 2927 3166 +3 164 2764 3299 +3 3211 2580 3674 +3 2866 2566 3565 +3 2219 2824 3713 +3 2446 3306 3503 +3 2534 2886 3376 +3 2675 2417 3215 +3 224 223 3301 +3 2680 2290 3395 +3 201 2676 3266 +3 2173 2751 2942 +3 2667 3458 3485 +3 2917 2217 3719 +3 2705 2170 3292 +3 157 3047 3194 +3 2530 2755 3718 +3 2682 2385 3121 +3 2421 3133 3155 +3 2281 2681 3161 +3 2422 2780 2916 +3 3192 2503 3404 +3 2710 214 3531 +3 2302 2711 3597 +3 3381 2385 3473 +3 2221 2702 3240 +3 2690 3071 3578 +3 2212 2794 3557 +3 2198 2712 3308 +3 2712 2452 3308 +3 2681 2208 3147 +3 2918 2168 3368 +3 2392 2823 2915 +3 2745 2194 3467 +3 2506 2745 3467 +3 2444 2727 2995 +3 2434 3014 3274 +3 2684 2292 3375 +3 2693 2427 3110 +3 2741 2290 3204 +3 2207 2737 3064 +3 2976 2389 3222 +3 2679 2443 3184 +3 2267 3243 3483 +3 2516 3014 3333 +3 2465 3371 3379 +3 153 154 2899 +3 2868 2344 3537 +3 2287 2709 3304 +3 2970 3015 3554 +3 2334 2769 2961 +3 3071 2222 3578 +3 2169 3077 3691 +3 2666 3142 3546 +3 3365 2984 3684 +3 2755 2213 3250 +3 2781 2312 3618 +3 2562 2781 3618 +3 2168 2918 3598 +3 2842 2274 3634 +3 3121 2277 3423 +3 2162 2787 3190 +3 2697 2388 3212 +3 2682 3121 3423 +3 3077 2733 3691 +3 2696 2188 3125 +3 2202 2698 3558 +3 2760 2209 2947 +3 2921 2165 3460 +3 2364 2681 3210 +3 2340 3128 3321 +3 2989 2680 3395 +3 2393 2761 3284 +3 2760 2394 3311 +3 2483 2919 3163 +3 2982 2253 3106 +3 2497 2982 3106 +3 2780 2422 3167 +3 2461 2731 3384 +3 3306 2646 3503 +3 2721 2209 3026 +3 2289 2698 3119 +3 2924 2179 2936 +3 2430 2924 2936 +3 2686 3585 3642 +3 2703 2260 3616 +3 2788 2406 3351 +3 2165 2938 3460 +3 250 2687 3399 +3 217 216 3390 +3 2193 2886 3543 +3 3116 2417 3349 +3 2351 2854 3265 +3 2725 2306 3629 +3 2398 2985 3006 +3 2330 2764 3754 +3 2594 3363 3467 +3 198 199 2851 +3 2241 2771 3344 +3 2494 3392 3448 +3 2495 2901 3287 +3 2426 2687 3491 +3 155 2732 3428 +3 2753 2214 3017 +3 2720 2290 3504 +3 2307 3620 3751 +3 2977 2403 3240 +3 2809 2419 2959 +3 2316 2809 2959 +3 2695 2299 3358 +3 2948 2679 3184 +3 2740 2190 3388 +3 2476 2740 3388 +3 2706 2191 3462 +3 2291 2898 3089 +3 2898 2460 3089 +3 2215 2786 2987 +3 3092 2743 3686 +3 2454 3128 3746 +3 2402 2773 3028 +3 2444 2954 3145 +3 185 186 2845 +3 3138 2629 3457 +3 2206 2998 3441 +3 2764 2466 3299 +3 2730 2252 3095 +3 2400 2730 3095 +3 2937 2230 3206 +3 2707 2321 3459 +3 3086 2167 3230 +3 2572 3086 3230 +3 2180 2756 3232 +3 2261 2973 3103 +3 2973 2491 3103 +3 248 247 2944 +3 2439 2964 3633 +3 2964 2693 3633 +3 2857 2348 3153 +3 2794 2388 3325 +3 2170 2705 3136 +3 3458 2495 3485 +3 166 167 3389 +3 2412 3150 3515 +3 2899 154 3428 +3 223 3097 3301 +3 2782 2352 2951 +3 2819 239 3635 +3 2743 2694 3686 +3 3171 2245 3403 +3 3413 2868 3537 +3 2540 2853 3427 +3 2853 2302 3427 +3 2766 2357 3726 +3 2725 2371 3062 +3 2252 2730 3723 +3 2377 2860 3012 +3 3017 2214 3182 +3 2720 2231 3400 +3 2353 2698 3224 +3 2875 2225 3512 +3 2841 2228 3503 +3 2742 2302 3597 +3 2823 3040 3563 +3 2364 2744 3676 +3 2917 2373 3313 +3 2337 3004 3507 +3 3004 2659 3507 +3 225 3335 3432 +3 2905 3079 3578 +3 2385 2949 3473 +3 2736 2424 3176 +3 2288 2736 3176 +3 2812 2215 2987 +3 2907 2555 3510 +3 2740 2476 3034 +3 2569 2931 3688 +3 2400 2746 3343 +3 3235 2454 3746 +3 2188 2708 3166 +3 2485 2983 3126 +3 2294 2768 3058 +3 2768 2472 3058 +3 3181 200 3266 +3 2714 2414 3180 +3 2977 3240 3712 +3 2701 2242 3454 +3 2886 2565 3543 +3 2326 2876 3010 +3 2876 2453 3010 +3 2838 2216 3457 +3 2585 2849 3701 +3 2546 3260 3695 +3 3166 2927 3496 +3 233 232 2866 +3 2501 2984 3365 +3 2411 2716 3129 +3 2702 2221 3320 +3 227 226 2869 +3 3013 2608 3401 +3 2449 3013 3401 +3 2821 2893 3641 +3 2216 2707 3200 +3 2543 2706 3628 +3 2437 2702 3320 +3 2558 2950 3418 +3 2315 2795 3006 +3 2795 2398 3006 +3 2471 3297 3407 +3 2313 2713 3149 +3 2723 2497 3537 +3 2887 2483 3209 +3 2377 2720 3504 +3 2589 2726 3553 +3 2421 2793 3087 +3 2793 2244 3087 +3 2706 2452 3243 +3 2727 2239 3193 +3 2216 3138 3457 +3 2931 2571 3709 +3 2547 3280 3453 +3 211 212 2908 +3 2890 2359 3114 +3 2196 2717 3478 +3 2442 2850 3081 +3 2850 2489 3081 +3 2712 2428 3483 +3 2561 2831 3740 +3 2775 2315 3006 +3 2560 2895 3678 +3 2673 3234 3514 +3 2708 2286 3626 +3 2627 3017 3182 +3 2192 2715 3445 +3 2458 2751 3296 +3 2751 2304 3296 +3 2457 3264 3490 +3 196 197 3019 +3 230 2746 3420 +3 2815 2384 2981 +3 2266 2728 3154 +3 2829 2378 3105 +3 3014 2516 3274 +3 229 228 2903 +3 2441 2947 3088 +3 2520 2746 3591 +3 2709 2372 3304 +3 2743 2222 3071 +3 2363 2811 2969 +3 187 188 3449 +3 2495 2813 3485 +3 3002 2207 3742 +3 2563 3137 3675 +3 2394 2728 3311 +3 2764 165 3031 +3 2237 2719 3164 +3 2358 2871 2923 +3 3143 2745 3489 +3 2757 2295 3326 +3 2755 3250 3718 +3 3032 2799 3271 +3 237 2901 3008 +3 2925 2263 3594 +3 2863 243 3551 +3 2868 2164 2979 +3 3363 2390 3636 +3 2622 3016 3339 +3 2731 2250 3130 +3 3074 2518 3122 +3 2440 3074 3122 +3 2262 2765 3037 +3 2924 2383 3431 +3 2950 2336 3418 +3 2227 2779 3046 +3 2841 2334 2961 +3 2240 3682 3687 +3 2375 2796 3187 +3 2554 2976 3407 +3 2932 2240 3687 +3 149 150 2894 +3 2559 2819 3635 +3 3550 2951 3646 +3 173 174 3116 +3 2796 2375 3288 +3 2542 3430 3486 +3 2783 2227 3046 +3 2728 2394 3154 +3 2535 2934 3638 +3 3234 2282 3514 +3 2209 2721 3679 +3 2806 2338 2988 +3 2924 2430 2925 +3 2383 2924 2925 +3 2536 2978 3167 +3 2168 2815 2981 +3 2175 2772 3236 +3 2746 2400 3095 +3 3053 2379 3566 +3 2225 3105 3512 +3 2413 2812 2987 +3 2833 2437 3244 +3 2386 2922 3571 +3 2814 2755 3352 +3 2378 2742 3597 +3 205 2883 3586 +3 2245 3036 3403 +3 2769 2470 3748 +3 2521 2864 3067 +3 2236 2941 3685 +3 2795 2315 3314 +3 2977 2565 3183 +3 2248 3038 3170 +3 2746 230 3343 +3 2283 2833 3643 +3 2301 2922 3721 +3 2922 2668 3721 +3 2426 3123 3399 +3 159 160 2904 +3 2300 2849 3417 +3 2229 2750 3104 +3 2750 2533 3104 +3 2273 2907 3510 +3 2485 3126 3373 +3 2365 2899 3346 +3 2899 2519 3346 +3 2666 3546 3631 +3 2892 2386 3186 +3 2504 2735 3761 +3 2224 2878 3324 +3 3047 2486 3194 +3 2723 2206 3441 +3 3362 2768 3372 +3 2998 2368 3475 +3 2390 3038 3636 +3 2433 2841 2961 +3 3108 2856 3350 +3 2778 2175 3236 +3 2946 170 3552 +3 2719 2374 3460 +3 2342 3142 3605 +3 2574 2878 3534 +3 2420 3131 3480 +3 3007 2455 3213 +3 2194 2745 3143 +3 3431 2383 3662 +3 2732 156 3194 +3 3302 2236 3685 +3 2840 3052 3446 +3 2213 2870 3250 +3 2676 3255 3282 +3 3255 2440 3282 +3 2833 2567 3643 +3 2190 2740 3160 +3 2953 2394 3331 +3 2393 2952 3330 +3 179 180 3129 +3 2827 2224 3153 +3 3439 2511 3653 +3 2722 2314 3310 +3 2714 3180 3532 +3 2473 3283 3717 +3 238 237 3008 +3 2830 2256 2986 +3 3089 2523 3445 +3 2727 2333 3426 +3 2755 2530 3640 +3 2901 2376 3008 +3 2519 2899 3428 +3 3268 2386 3571 +3 2387 2783 3046 +3 3163 2919 3515 +3 2831 2541 3731 +3 3169 2619 3522 +3 2795 2252 3723 +3 2511 3195 3653 +3 2397 2830 2986 +3 2234 2725 3273 +3 2794 2212 3212 +3 2252 2795 3756 +3 2846 2355 3246 +3 3180 2217 3532 +3 2387 2799 3032 +3 243 242 3551 +3 2730 2400 3668 +3 2780 3167 3541 +3 2791 279 3060 +3 261 2792 3061 +3 2750 2229 3584 +3 2881 2766 3726 +3 2515 3045 3218 +3 2195 2954 2995 +3 2954 2444 2995 +3 3335 2618 3432 +3 2877 2402 3028 +3 2985 2540 3427 +3 2392 3024 3558 +3 2414 2963 3090 +3 2728 2462 3479 +3 3585 2308 3642 +3 2744 2174 3447 +3 2737 2547 3453 +3 204 205 3586 +3 3092 2410 3482 +3 2664 3092 3482 +3 2442 2890 3114 +3 3539 2409 3639 +3 3040 2392 3558 +3 2422 2916 3158 +3 3067 2583 3342 +3 2269 3067 3342 +3 2311 2909 3534 +3 2909 2574 3534 +3 2396 2791 3060 +3 2792 2395 3061 +3 2941 2236 3029 +3 2498 2941 3029 +3 2777 2265 3219 +3 2764 3031 3754 +3 2285 2897 3491 +3 2321 2797 3057 +3 2960 2541 2996 +3 2892 2418 3414 +3 2339 2891 2964 +3 210 2747 3369 +3 2443 2817 3184 +3 2817 2338 3184 +3 2406 2992 3351 +3 2915 2297 3198 +3 2214 2753 3158 +3 2312 2781 3078 +3 2757 3326 3405 +3 2165 2951 3550 +3 2828 2501 3086 +3 2739 2456 3372 +3 2437 2738 3329 +3 2463 2741 3204 +3 3153 2348 3404 +3 3230 2167 3244 +3 252 251 3123 +3 2907 2637 3392 +3 2936 2608 3323 +3 224 2739 3335 +3 3186 2474 3579 +3 2224 2857 3153 +3 2873 2390 3657 +3 2295 2757 3145 +3 2361 2770 3719 +3 2436 2774 3577 +3 2686 2980 3585 +3 2232 2768 3362 +3 2754 2175 3281 +3 2858 2402 3005 +3 2765 2502 3475 +3 3156 2448 3175 +3 2201 2810 3276 +3 2776 2257 3745 +3 2771 2332 3344 +3 2539 3181 3266 +3 3018 2718 3619 +3 3283 2662 3717 +3 2771 2449 3677 +3 2332 2771 3678 +3 2738 2437 3320 +3 2360 2794 3325 +3 2429 2782 3520 +3 2456 2739 3301 +3 2582 2966 3673 +3 2887 3209 3716 +3 2738 2442 3650 +3 2221 2738 3320 +3 2849 2585 3087 +3 2244 2849 3087 +3 2762 2210 3159 +3 2767 2441 3168 +3 218 2767 3168 +3 2777 2393 3284 +3 3363 2506 3467 +3 2775 2403 3183 +3 2523 3089 3171 +3 3089 2460 3171 +3 2854 2351 3340 +3 2469 2935 3125 +3 3485 2813 3665 +3 2306 3062 3700 +3 3088 2947 3679 +3 2749 195 3239 +3 2333 3193 3683 +3 2435 2778 3652 +3 194 2749 3241 +3 2790 2383 3101 +3 2603 3139 3318 +3 3139 2270 3318 +3 215 3444 3531 +3 2791 2396 3100 +3 2395 2792 3099 +3 2181 2858 3005 +3 3088 2721 3642 +3 2308 3088 3642 +3 2302 2742 3427 +3 2391 2865 3336 +3 2456 3362 3372 +3 3177 2689 3451 +3 2477 3177 3451 +3 3047 2545 3256 +3 2486 3047 3256 +3 2772 2350 3644 +3 2959 2419 3182 +3 2433 2961 3107 +3 2297 2743 3336 +3 2837 2181 3419 +3 198 2851 3556 +3 2176 2847 3032 +3 2960 2365 3346 +3 221 220 3063 +3 2388 3009 3325 +3 264 2839 3529 +3 2746 2520 3420 +3 269 3280 3291 +3 2788 2319 3117 +3 2406 2788 3117 +3 3058 2472 3625 +3 3380 2468 3676 +3 2502 2765 3569 +3 3366 2869 3555 +3 2744 3380 3676 +3 3652 2778 3760 +3 2357 2779 3726 +3 2423 3093 3508 +3 243 2863 3208 +3 2531 3063 3585 +3 2615 2992 3542 +3 2992 2279 3542 +3 2751 2173 3261 +3 2430 2763 3435 +3 2787 2162 3128 +3 2409 3023 3639 +3 2747 2459 3369 +3 2304 2751 3499 +3 2472 3370 3625 +3 2448 2750 3584 +3 2216 2781 3138 +3 2786 2215 3146 +3 2327 2906 3202 +3 2906 2469 3202 +3 2774 182 3577 +3 2357 2766 3595 +3 3491 2687 3656 +3 259 258 2952 +3 282 281 2953 +3 2785 2466 3604 +3 2986 2654 3606 +3 2315 2886 3314 +3 2419 2809 3126 +3 2809 2166 3126 +3 2337 2934 3004 +3 2934 2561 3004 +3 2831 2319 3740 +3 2756 2366 3232 +3 2801 2162 3225 +3 2315 2775 3183 +3 3084 2499 3264 +3 2422 3158 3172 +3 2228 2800 3115 +3 192 193 3227 +3 2162 2802 3225 +3 2774 2436 3663 +3 2784 2340 3206 +3 3039 2276 3596 +3 2428 2844 3094 +3 2844 2243 3094 +3 2407 2754 3281 +3 2779 2427 3607 +3 2231 2836 3400 +3 2549 3559 3655 +3 3213 2455 3654 +3 2366 2756 3517 +3 3647 3214 3652 +3 2974 2220 3222 +3 2381 2838 3457 +3 2903 228 3366 +3 2220 2867 3075 +3 2443 3144 3165 +3 2851 2538 3556 +3 2832 2532 3545 +3 2203 2832 3545 +3 3030 2241 3344 +3 2557 3652 3760 +3 2853 2473 3160 +3 188 189 3093 +3 268 267 2966 +3 2631 3098 3430 +3 2810 2379 3276 +3 2490 2918 3368 +3 2625 2753 3605 +3 2538 3178 3293 +3 2817 2247 3205 +3 2839 2312 3513 +3 2529 2839 3513 +3 2180 2969 3355 +3 2322 3214 3647 +3 2217 2808 3532 +3 2808 2512 3532 +3 2192 3127 3708 +3 4 254 3382 +3 176 4 3382 +3 2404 2944 3111 +3 2331 2816 3671 +3 2211 2807 3278 +3 2911 2207 3570 +3 3136 2353 3337 +3 2374 2877 3028 +3 2857 2408 3079 +3 2232 2940 3048 +3 2384 2815 3139 +3 3110 2182 3217 +3 2235 2763 3285 +3 2275 3169 3522 +3 2772 2462 3506 +3 2553 2762 3651 +3 2322 2825 3175 +3 2999 2244 3188 +3 2393 2777 3219 +3 3142 2625 3605 +3 2759 3144 3707 +3 3144 2318 3707 +3 2761 2208 3284 +3 2903 2400 3343 +3 2895 2332 3678 +3 2763 2430 3285 +3 2861 2415 3051 +3 3519 2553 3649 +3 2799 2246 3482 +3 2177 2757 3405 +3 3186 2386 3268 +3 2943 2275 3522 +3 248 2944 3549 +3 2209 2760 3311 +3 2390 2873 3038 +3 3117 2831 3731 +3 2787 2361 3190 +3 2856 2399 3132 +3 2479 2759 3707 +3 2174 2797 3447 +3 3148 2263 3435 +3 2317 2801 3624 +3 3108 2262 3316 +3 266 265 3257 +3 2441 2767 3474 +3 2570 2898 3295 +3 2898 2291 3295 +3 2857 2224 3134 +3 2244 2793 3188 +3 2526 2790 3666 +3 2398 2795 3723 +3 2767 2329 3474 +3 2816 2900 3671 +3 2498 2903 3366 +3 2802 2305 3612 +3 2522 2802 3612 +3 2765 2488 3353 +3 3517 2575 3733 +3 2845 2549 3655 +3 2796 2325 3187 +3 2310 2798 3579 +3 2885 2221 3240 +3 3264 2499 3442 +3 2968 2406 3463 +3 2225 2829 3105 +3 3317 2617 3370 +3 2242 3034 3341 +3 2849 2244 3332 +3 2480 2849 3332 +3 227 2869 3366 +3 2843 2322 3175 +3 2397 2975 3189 +3 2768 2294 3372 +3 2510 3035 3704 +3 2402 2877 3564 +3 3582 2282 3672 +3 2568 2776 3539 +3 2164 2769 3748 +3 2801 2626 3746 +3 2338 2948 3184 +3 151 152 3345 +3 2388 2794 3212 +3 2348 2857 3079 +3 2962 2399 3570 +3 2586 2962 3570 +3 161 162 3049 +3 233 2866 3565 +3 168 169 3109 +3 2867 2405 3075 +3 169 2946 3109 +3 3267 2258 3298 +3 2893 2357 3641 +3 2804 2307 3640 +3 2530 2804 3640 +3 2319 2831 3117 +3 2365 2960 2996 +3 2462 2772 3644 +3 2312 2776 3513 +3 2242 2782 3454 +3 2790 2526 3662 +3 2383 2790 3662 +3 209 210 3369 +3 2839 264 3312 +3 2349 3248 3750 +3 165 166 3031 +3 2183 2856 3132 +3 3185 2435 3214 +3 156 157 3194 +3 2509 3322 3338 +3 2545 2950 3256 +3 2950 2251 3256 +3 2913 2478 3252 +3 2341 2913 3252 +3 2425 2819 3148 +3 2492 2802 3593 +3 2206 2803 3757 +3 2413 3560 3699 +3 2880 2354 3082 +3 2455 3277 3654 +3 2331 2845 3655 +3 2276 3039 3654 +3 2432 2930 3076 +3 2930 2253 3076 +3 2977 2283 3495 +3 2565 2977 3495 +3 2774 2672 3433 +3 244 243 3208 +3 182 2774 3433 +3 3546 2524 3631 +3 214 215 3531 +3 2468 2777 3377 +3 2667 3020 3458 +3 2405 3036 3075 +3 3036 2471 3075 +3 3027 2513 3551 +3 3494 2510 3704 +3 2952 2576 3702 +3 2577 2953 3703 +3 265 264 3529 +3 2420 2880 3082 +3 2946 2401 3109 +3 2314 2785 3472 +3 2804 270 3291 +3 2592 2786 3611 +3 2656 3220 3559 +3 2551 2943 3522 +3 2825 2413 3398 +3 2199 2822 3645 +3 195 196 3239 +3 193 194 3241 +3 3110 3217 3633 +3 3533 2663 3575 +3 2503 2827 3153 +3 2499 2790 3442 +3 2849 2480 3417 +3 2816 2481 3189 +3 2418 2822 3416 +3 2802 2522 3225 +3 2162 3190 3593 +3 2475 2800 3238 +3 2380 2870 3098 +3 2864 2229 3104 +3 3041 2185 3270 +3 2528 2780 3541 +3 2181 2837 3315 +3 2600 3039 3596 +3 2633 3044 3632 +3 2637 3157 3448 +3 3157 2187 3448 +3 2359 2858 3114 +3 2643 2995 3426 +3 2782 2242 3523 +3 159 2904 3436 +3 183 184 3070 +3 3065 2448 3156 +3 2493 3065 3156 +3 2505 3062 3367 +3 2876 2268 3233 +3 2453 2876 3233 +3 2800 2475 3459 +3 2321 2800 3459 +3 2277 3121 3524 +3 2285 3491 3656 +3 2507 3179 3478 +3 2335 3178 3755 +3 2234 2888 3468 +3 2424 3124 3279 +3 3124 2550 3279 +3 2177 2796 3288 +3 2797 2381 3447 +3 2826 2217 3180 +3 2781 2562 3568 +3 3113 2398 3723 +3 2730 3113 3723 +3 2824 2219 3364 +3 2238 2896 3152 +3 2896 2439 3152 +3 2782 2429 3454 +3 2850 2181 3315 +3 2427 2893 3110 +3 2415 2861 3609 +3 2555 2907 3754 +3 3178 2264 3293 +3 2983 2254 3724 +3 2819 2425 3488 +3 2894 150 3455 +3 2366 2939 3056 +3 2171 2788 3351 +3 2731 3083 3384 +3 3103 2491 3259 +3 2996 2255 3328 +3 2233 2798 3300 +3 2408 2857 3134 +3 2181 3005 3419 +3 2837 2408 3315 +3 2412 2919 3540 +3 2212 2956 3212 +3 2355 2872 3327 +3 231 230 3420 +3 2552 3203 3481 +3 3171 2460 3269 +3 2234 2785 3604 +3 3072 2594 3467 +3 3121 2640 3524 +3 2794 2360 3557 +3 3560 2758 3699 +3 3016 2169 3576 +3 2517 2807 3263 +3 3071 2391 3336 +3 279 278 3060 +3 262 261 3061 +3 2575 3001 3511 +3 3001 2279 3511 +3 2294 3042 3714 +3 1 146 3444 +3 215 1 3444 +3 2808 2487 3267 +3 157 158 3047 +3 2790 2499 3391 +3 199 200 3181 +3 2433 2930 3743 +3 2597 3222 3687 +3 2893 2182 3110 +3 2472 3317 3370 +3 2528 3393 3471 +3 3409 2231 3680 +3 2612 3612 3661 +3 3012 2641 3371 +3 2807 2404 3278 +3 2296 3365 3684 +3 2448 2843 3175 +3 2908 2477 3451 +3 2498 3366 3555 +3 2447 2928 3410 +3 2833 3244 3590 +3 3012 2860 3596 +3 3478 3179 3752 +3 2982 2723 3441 +3 2793 2421 3471 +3 2163 3025 3140 +3 3007 2612 3610 +3 2304 3007 3610 +3 235 2813 3287 +3 2813 2495 3287 +3 3227 193 3241 +3 2795 3314 3756 +3 3130 2250 3237 +3 2202 2854 3279 +3 2854 2202 3265 +3 232 231 3303 +3 2820 2346 3226 +3 2404 2807 3637 +3 2807 2517 3637 +3 2307 2804 3620 +3 3078 2409 3539 +3 3326 2450 3405 +3 3057 2446 3115 +3 3163 2590 3373 +3 2166 3163 3373 +3 2502 2982 3441 +3 2802 2162 3593 +3 2762 3440 3494 +3 2960 2204 3463 +3 2541 2960 3463 +3 184 185 3623 +3 2174 2835 3247 +3 2835 2445 3247 +3 2282 2910 3672 +3 2477 2908 3307 +3 2908 212 3307 +3 2549 2845 3696 +3 3308 2452 3484 +3 2756 3001 3517 +3 3429 2729 3744 +3 2211 3278 3609 +3 3135 2432 3238 +3 3167 2172 3541 +3 2930 2433 3106 +3 2253 2930 3106 +3 2487 2808 3313 +3 3280 2547 3291 +3 2806 2496 3613 +3 2210 2880 3480 +3 3352 2755 3640 +3 269 268 3280 +3 2410 2799 3482 +3 3463 2406 3731 +3 3440 2510 3494 +3 2399 2962 3132 +3 2851 199 3181 +3 2911 2399 3108 +3 226 225 3432 +3 2944 247 3111 +3 2770 2917 3719 +3 2813 2566 3665 +3 2812 2322 3647 +3 3005 2620 3419 +3 247 246 3111 +3 2922 2386 3120 +3 2518 3074 3586 +3 3268 2683 3437 +3 2474 3268 3437 +3 2338 2806 3613 +3 2354 2958 3082 +3 258 257 3330 +3 283 282 3331 +3 148 149 3465 +3 2325 2805 3438 +3 3136 2509 3165 +3 2170 3136 3165 +3 2994 2384 3179 +3 2782 2951 3520 +3 2613 3101 3594 +3 2958 2546 3082 +3 2322 2843 3214 +3 2527 3473 3690 +3 2897 2660 3589 +3 2815 2505 3664 +3 3152 2666 3631 +3 2845 186 3696 +3 2822 2199 3741 +3 3245 2652 3698 +3 2625 2821 3737 +3 2307 3352 3640 +3 2215 2812 3711 +3 2724 3409 3680 +3 2587 2814 3352 +3 3576 2169 3691 +3 2346 2810 3434 +3 2902 2298 3297 +3 2471 2902 3297 +3 2817 2443 3338 +3 2505 2815 3598 +3 2815 2168 3598 +3 2746 3095 3591 +3 2176 3271 3583 +3 3039 2602 3654 +3 2883 205 3286 +3 2929 2411 3147 +3 2913 2194 3143 +3 3158 2916 3669 +3 2874 2226 3383 +3 2478 2874 3383 +3 2663 3133 3575 +3 3133 2191 3575 +3 3223 209 3369 +3 2446 3057 3249 +3 2957 2234 3468 +3 2324 2965 3588 +3 259 2952 3702 +3 2953 281 3703 +3 2992 2615 3351 +3 2428 2887 3483 +3 230 229 3343 +3 2543 3216 3533 +3 2461 2830 3270 +3 3000 2380 3229 +3 2478 2913 3143 +3 3425 2514 3438 +3 2228 2841 3743 +3 264 263 3312 +3 2327 2863 3530 +3 2863 2513 3530 +3 2256 2830 3384 +3 2830 2461 3384 +3 2824 2362 3713 +3 3417 2749 3439 +3 2300 3417 3439 +3 2492 2826 3516 +3 3207 2465 3379 +3 2999 2628 3332 +3 2912 2387 3607 +3 3023 2475 3068 +3 2457 2840 3681 +3 2966 267 3673 +3 2930 2432 3135 +3 2233 2892 3186 +3 2956 2697 3212 +3 2863 2327 3734 +3 2816 2331 3525 +3 275 3228 3251 +3 2339 2848 3422 +3 2965 2324 3548 +3 2481 2816 3525 +3 2199 3004 3741 +3 2934 2337 3638 +3 3523 2583 3581 +3 241 240 3488 +3 2264 3178 3484 +3 3178 2635 3484 +3 2288 3176 3275 +3 3176 2548 3275 +3 2894 3455 3638 +3 2822 2418 3645 +3 2183 3023 3068 +3 2632 2821 3641 +3 2501 2828 3725 +3 2826 2361 3719 +3 2481 3041 3189 +3 3041 2397 3189 +3 2423 2824 3364 +3 3220 2274 3559 +3 2522 2874 3624 +3 2949 2536 3118 +3 3485 2278 3490 +3 2635 3308 3484 +3 2831 2255 3753 +3 2541 2831 3753 +3 2823 2176 3583 +3 2954 2195 3599 +3 2564 2954 3599 +3 2959 3182 3505 +3 2180 3232 3759 +3 2832 2340 3321 +3 2556 2955 3462 +3 3271 2694 3583 +3 3042 2618 3714 +3 2926 2610 3561 +3 2298 2902 3477 +3 2902 2507 3477 +3 3257 265 3529 +3 2974 3222 3562 +3 2832 2203 3728 +3 2601 3073 3258 +3 3170 2532 3235 +3 2248 3170 3235 +3 2818 2470 3690 +3 2933 2199 3645 +3 3236 2382 3760 +3 2778 3236 3760 +3 2184 2825 3398 +3 240 2819 3488 +3 2647 2823 3563 +3 2897 2426 3491 +3 2226 3213 3383 +3 3213 2602 3383 +3 3356 2484 3408 +3 2165 2921 3520 +3 2895 2451 3258 +3 2332 2895 3258 +3 2930 3135 3743 +3 2701 3454 3512 +3 2884 2437 3329 +3 2612 3290 3612 +3 2941 2345 3685 +3 3278 2671 3609 +3 2254 3014 3305 +3 2870 2380 3250 +3 2854 2424 3279 +3 3228 2631 3430 +3 2542 3228 3430 +3 2843 2448 3584 +3 3199 2198 3308 +3 2635 3199 3308 +3 2962 2568 3132 +3 2871 2358 3253 +3 2410 3092 3686 +3 2403 2885 3240 +3 2537 3011 3151 +3 2464 2836 3409 +3 2836 2231 3409 +3 3074 2440 3255 +3 3068 2432 3201 +3 3328 2535 3345 +3 2650 3328 3345 +3 2882 2596 3260 +3 2910 2645 3374 +3 2989 2434 3274 +3 170 171 3552 +3 2905 2222 3357 +3 2437 2884 3244 +3 2983 2419 3126 +3 2432 3076 3201 +3 3207 2724 3680 +3 2465 3207 3680 +3 2889 276 3251 +3 3340 2351 3730 +3 2907 2330 3754 +3 3436 2904 3622 +3 2403 2977 3183 +3 2392 2915 3198 +3 3521 2688 3674 +3 2828 2249 3725 +3 2473 2853 3302 +3 2161 2848 3319 +3 2350 3026 3644 +3 3228 2542 3251 +3 3303 231 3420 +3 152 153 3289 +3 2379 2828 3566 +3 2341 3039 3603 +3 3039 2600 3603 +3 2827 2311 3534 +3 2533 3550 3646 +3 2891 2339 3422 +3 182 183 3577 +3 2841 2433 3743 +3 2925 2430 3435 +3 2901 2495 3458 +3 2376 2901 3458 +3 2546 2882 3260 +3 3067 2864 3581 +3 3070 2436 3577 +3 219 218 3168 +3 2943 2327 3202 +3 2588 2943 3202 +3 2279 2992 3511 +3 2532 2832 3648 +3 2401 2946 3440 +3 2946 2510 3440 +3 2874 2317 3624 +3 2279 3162 3542 +3 2436 2900 3464 +3 2193 2840 3446 +3 3098 2259 3430 +3 3508 190 3619 +3 3033 2663 3533 +3 3116 2665 3672 +3 2417 3116 3672 +3 2865 2620 3406 +3 2279 3001 3162 +3 3072 2194 3614 +3 2509 3136 3337 +3 2567 2833 3590 +3 3027 241 3488 +3 2866 232 3303 +3 2391 2837 3419 +3 2944 2517 3549 +3 2951 2165 3520 +3 2704 2846 3732 +3 2424 2854 3340 +3 2510 2946 3552 +3 2438 3045 3500 +3 2864 2352 3581 +3 3050 2438 3500 +3 2914 2346 3231 +3 2449 2914 3231 +3 275 274 3228 +3 3359 2298 3477 +3 2717 3359 3477 +3 2545 3047 3436 +3 3047 158 3436 +3 205 206 3286 +3 2835 2364 3481 +3 2223 2975 3203 +3 2856 2488 3350 +3 3119 2353 3535 +3 2379 3053 3276 +3 2955 2706 3462 +3 2358 2967 3253 +3 2967 2482 3253 +3 2978 2172 3167 +3 3115 2446 3503 +3 3125 2935 3617 +3 2735 2865 3406 +3 3162 2614 3542 +3 3037 2765 3475 +3 2873 2177 3405 +3 2595 2937 3206 +3 3162 2447 3410 +3 2865 2297 3336 +3 2413 2987 3560 +3 2739 3372 3714 +3 2848 2431 3422 +3 2543 3533 3575 +3 3204 2720 3400 +3 2871 2240 3456 +3 2851 2335 3755 +3 2538 2851 3755 +3 2527 3381 3473 +3 3092 2664 3357 +3 2665 3582 3672 +3 2872 2416 3327 +3 3454 2429 3512 +3 2485 3196 3333 +3 2855 2356 3393 +3 2844 2325 3632 +3 2839 2529 3529 +3 2312 2839 3618 +3 185 2845 3623 +3 3630 2677 3757 +3 2347 3141 3736 +3 3141 2696 3736 +3 2461 3270 3675 +3 2229 2843 3584 +3 3001 2447 3162 +3 2886 2534 3314 +3 2563 3050 3500 +3 3025 2554 3140 +3 3011 2239 3151 +3 200 201 3266 +3 2260 2884 3329 +3 2965 2534 3588 +3 262 3061 3476 +3 2436 2997 3663 +3 2348 2862 3404 +3 2915 2823 3583 +3 270 269 3291 +3 3106 2433 3107 +3 2497 3106 3107 +3 153 2899 3289 +3 2489 2850 3693 +3 3046 2779 3607 +3 2455 3007 3499 +3 2459 3149 3300 +3 2453 2884 3705 +3 171 3035 3552 +3 2996 2541 3753 +3 3060 278 3602 +3 2387 3046 3607 +3 2239 3122 3193 +3 2667 3485 3490 +3 2164 2868 3413 +3 2179 2914 3401 +3 2591 2989 3395 +3 2481 3525 3634 +3 2507 2994 3179 +3 2475 3411 3459 +3 3525 2842 3634 +3 2981 2384 3269 +3 2975 2445 3203 +3 3444 2569 3531 +3 2499 2984 3391 +3 2984 2249 3391 +3 2450 2873 3405 +3 3545 2532 3735 +3 2202 3024 3265 +3 3019 2538 3293 +3 3374 2645 3589 +3 3411 2707 3459 +3 2869 226 3432 +3 2183 3068 3201 +3 3252 2478 3383 +3 2602 3252 3383 +3 2983 2485 3333 +3 2254 2983 3333 +3 2867 2458 3749 +3 2520 2965 3548 +3 2503 3153 3404 +3 2563 3500 3524 +3 2891 2246 3762 +3 3001 2575 3517 +3 2687 3066 3656 +3 2324 2866 3548 +3 249 248 3549 +3 3064 2737 3453 +3 2487 3313 3355 +3 2969 2180 3759 +3 3209 2593 3716 +3 2451 2871 3456 +3 2493 2988 3205 +3 2860 2600 3596 +3 2861 2211 3609 +3 3016 2416 3339 +3 3034 2476 3341 +3 2648 2936 3323 +3 229 2903 3343 +3 3266 2676 3528 +3 2539 3266 3528 +3 2513 2863 3551 +3 3372 2294 3714 +3 2220 2976 3222 +3 181 3433 3450 +3 2405 2867 3615 +3 225 224 3335 +3 2870 2496 3697 +3 2975 2397 3606 +3 2550 3322 3337 +3 2888 2234 3604 +3 2386 2892 3414 +3 2874 2478 3489 +3 2317 2874 3489 +3 3126 2166 3373 +3 2869 2345 3555 +3 2431 2905 3357 +3 2968 2204 3733 +3 2575 2968 3733 +3 189 190 3508 +3 276 275 3251 +3 3068 2475 3238 +3 2914 2179 3587 +3 2606 3495 3643 +3 2339 2896 3408 +3 2718 3508 3619 +3 2880 2420 3480 +3 2177 2873 3657 +3 3275 2548 3550 +3 2429 2875 3512 +3 2582 3257 3360 +3 3257 2529 3360 +3 2460 2981 3269 +3 2336 2950 3622 +3 2950 2545 3622 +3 2681 3147 3161 +3 2596 2970 3554 +3 2397 2986 3606 +3 3348 2306 3487 +3 2688 3348 3487 +3 2425 3027 3488 +3 3085 2310 3579 +3 2877 2237 3564 +3 2950 2558 3658 +3 6 285 3600 +3 216 6 3600 +3 5 177 3601 +3 255 5 3601 +3 2884 2260 3705 +3 3127 2405 3615 +3 3248 2622 3750 +3 2176 3032 3271 +3 2432 3068 3238 +3 2883 2333 3683 +3 3101 2383 3594 +3 2887 2267 3483 +3 2330 2907 3392 +3 3245 2704 3649 +3 2553 3245 3649 +3 2670 3220 3364 +3 3220 2423 3364 +3 149 2894 3465 +3 2267 2887 3716 +3 2363 2969 3469 +3 2997 2436 3464 +3 2469 2906 3424 +3 3104 2533 3646 +3 2689 3177 3526 +3 3433 2672 3450 +3 2906 2235 3424 +3 3059 2582 3360 +3 2257 3059 3360 +3 2306 2918 3487 +3 2918 2490 3487 +3 3131 2420 3157 +3 2637 3131 3157 +3 236 235 3287 +3 2973 2349 3415 +3 2491 2973 3415 +3 3347 2287 3386 +3 2262 3108 3350 +3 3416 2822 3740 +3 2319 3416 3740 +3 2938 2719 3460 +3 2523 3171 3403 +3 2466 2888 3604 +3 3029 2236 3668 +3 3039 2341 3252 +3 2602 3039 3252 +3 2900 2223 3464 +3 2400 3029 3668 +3 2240 2932 3456 +3 2914 2449 3401 +3 2607 3173 3510 +3 3173 2273 3510 +3 268 2966 3280 +3 3004 2561 3741 +3 163 164 3299 +3 2947 2441 3474 +3 3042 2662 3283 +3 3323 2608 3358 +3 2299 3323 3358 +3 3085 2474 3437 +3 212 213 3307 +3 2452 2955 3484 +3 2409 3078 3200 +3 3112 2617 3317 +3 3134 2224 3324 +3 2927 2588 3496 +3 2801 3225 3624 +3 2570 3295 3298 +3 3295 2512 3298 +3 2276 3012 3596 +3 3008 2559 3635 +3 238 3008 3635 +3 2828 3086 3566 +3 3147 2411 3161 +3 2286 3051 3626 +3 2337 2894 3638 +3 2990 2363 3469 +3 2474 3186 3268 +3 147 2931 3536 +3 2931 2569 3536 +3 2484 3319 3408 +3 251 250 3399 +3 2608 3013 3358 +3 3689 2196 3752 +3 3076 2488 3201 +3 2278 3485 3665 +3 3550 2548 3706 +3 3045 2438 3218 +3 2404 3169 3278 +3 3169 2671 3278 +3 2580 3043 3674 +3 3043 2200 3674 +3 2480 3227 3241 +3 2842 3525 3655 +3 3525 2331 3655 +3 2943 2551 3734 +3 2327 2943 3734 +3 272 271 3498 +3 2277 3045 3423 +3 3045 2515 3423 +3 2645 2897 3589 +3 2928 2230 3410 +3 2189 2989 3274 +3 2384 2994 3269 +3 3259 2196 3689 +3 2704 3245 3698 +3 2345 3283 3685 +3 2900 2621 3671 +3 2507 2902 3592 +3 2906 2327 3530 +3 172 173 3349 +3 2222 2905 3578 +3 2911 2479 3742 +3 3040 2289 3563 +3 2182 3142 3217 +3 3142 2666 3217 +3 2952 258 3330 +3 282 2953 3331 +3 2179 2924 3431 +3 2920 2605 3538 +3 207 2920 3538 +3 2904 2336 3622 +3 2263 2925 3435 +3 2998 2206 3334 +3 2945 2180 3355 +3 2222 3092 3357 +3 3122 2518 3193 +3 2200 3521 3674 +3 3066 249 3549 +3 180 181 3450 +3 3586 2883 3683 +3 2518 3586 3683 +3 2374 2921 3460 +3 228 227 3366 +3 3253 2482 3385 +3 3097 2456 3301 +3 2463 3191 3192 +3 3191 2503 3192 +3 2935 2469 3424 +3 3024 2504 3265 +3 2278 3052 3490 +3 3292 2368 3509 +3 2705 3292 3509 +3 2399 2911 3570 +3 2409 3200 3411 +3 3294 2591 3395 +3 2290 3294 3395 +3 2976 2220 3407 +3 2236 3113 3668 +3 3486 2758 3560 +3 2323 3486 3560 +3 2197 3374 3589 +3 2964 2891 3762 +3 2483 3163 3209 +3 3163 2166 3209 +3 2207 2911 3742 +3 3398 2413 3699 +3 2910 2417 3672 +3 2427 2912 3607 +3 2972 2468 3377 +3 3322 2509 3337 +3 2991 2377 3371 +3 2919 2412 3515 +3 3200 2707 3411 +3 3309 2606 3643 +3 2220 3075 3407 +3 2971 2382 3506 +3 2259 3098 3697 +3 2694 2915 3583 +3 2550 3124 3322 +3 2252 2965 3591 +3 2965 2520 3591 +3 3261 2455 3499 +3 2990 2525 3574 +3 2251 2990 3574 +3 3084 2457 3681 +3 3003 2468 3380 +3 2921 2429 3520 +3 2919 2243 3540 +3 3215 2284 3704 +3 2675 3215 3704 +3 2970 2270 3367 +3 3063 2531 3493 +3 221 3063 3493 +3 2251 2950 3658 +3 2916 2579 3669 +3 181 182 3433 +3 3176 2424 3340 +3 2548 3176 3340 +3 2208 2972 3377 +3 2183 3132 3639 +3 2511 3019 3293 +3 3000 272 3498 +3 2405 3127 3403 +3 3127 2523 3403 +3 2568 3539 3639 +3 2980 2232 3362 +3 154 155 3428 +3 2918 2505 3598 +3 3051 2415 3626 +3 190 191 3619 +3 2922 2301 3571 +3 2505 2918 3700 +3 3418 2336 3573 +3 2722 3418 3573 +3 3077 2354 3739 +3 2733 3077 3739 +3 150 151 3455 +3 2538 3019 3556 +3 3019 197 3556 +3 3014 2434 3305 +3 3393 2528 3541 +3 158 159 3436 +3 2333 3397 3426 +3 3397 2643 3426 +3 3135 2228 3743 +3 3053 2623 3276 +3 2188 3496 3527 +3 2244 2999 3332 +3 2588 3202 3527 +3 3202 2469 3527 +3 2918 2306 3700 +3 2685 3346 3567 +3 3346 2519 3567 +3 3073 2332 3258 +3 2345 2941 3555 +3 2941 2498 3555 +3 2993 2464 3347 +3 2508 2998 3334 +3 2706 3243 3628 +3 2383 2925 3594 +3 2369 3064 3453 +3 2468 2972 3676 +3 3208 2863 3734 +3 3009 2581 3325 +3 2345 3042 3283 +3 2489 3324 3616 +3 3324 2703 3616 +3 3392 2494 3468 +3 2462 3026 3479 +3 2377 3012 3371 +3 2668 2922 3710 +3 2231 2991 3680 +3 2457 3084 3264 +3 3368 2570 3466 +3 2465 2991 3371 +3 3429 2564 3580 +3 2729 3429 3580 +3 3010 2453 3705 +3 3455 2535 3638 +3 2790 3391 3666 +3 2979 2164 3748 +3 2995 2727 3426 +3 222 221 3493 +3 2694 3271 3686 +3 3271 2410 3686 +3 263 262 3476 +3 2935 2299 3617 +3 2614 3162 3410 +3 2790 3101 3442 +3 3310 2500 3521 +3 2949 2218 3473 +3 3014 2254 3333 +3 171 172 3747 +3 2765 3353 3569 +3 2467 3103 3259 +3 3048 2407 3317 +3 186 187 3696 +3 3682 2597 3687 +3 2167 3086 3394 +3 3086 2501 3394 +3 2381 3003 3380 +3 2494 2957 3468 +3 2955 2264 3484 +3 2489 3134 3324 +3 3348 2688 3521 +3 2998 2508 3509 +3 2368 2998 3509 +3 2185 3050 3675 +3 3050 2563 3675 +3 2525 3361 3574 +3 3361 2684 3574 +3 3120 2386 3414 +3 2944 2404 3637 +3 2517 2944 3637 +3 2753 3017 3605 +3 2204 2968 3463 +3 2472 3048 3317 +3 2389 2932 3687 +3 3128 2454 3321 +3 3365 2567 3394 +3 2657 3030 3344 +3 3076 2253 3353 +3 2488 3076 3353 +3 2351 2938 3730 +3 146 147 3536 +3 2532 3170 3735 +3 206 207 3538 +3 2264 3195 3293 +3 3195 2511 3293 +3 2938 2165 3706 +3 3125 2188 3527 +3 2442 3081 3650 +3 3174 2524 3305 +3 2434 3174 3305 +3 2579 2959 3505 +3 2353 3224 3337 +3 3224 2550 3337 +3 197 198 3556 +3 2366 3056 3361 +3 2204 2939 3733 +3 234 233 3565 +3 2198 3199 3425 +3 3199 2636 3425 +3 2578 3296 3412 +3 3296 2304 3412 +3 3247 2654 3249 +3 2174 3247 3249 +3 2531 2980 3627 +3 2556 3378 3701 +3 2743 3071 3336 +3 3051 2286 3339 +3 3056 2684 3361 +3 2948 2338 3613 +3 2372 2974 3562 +3 2475 3023 3411 +3 3015 2494 3448 +3 2187 3015 3448 +3 2462 2971 3506 +3 3127 2192 3445 +3 2523 3127 3445 +3 3132 2568 3639 +3 278 277 3602 +3 2968 2575 3511 +3 2271 3055 3492 +3 3055 2514 3492 +3 3086 2572 3566 +3 2616 3120 3414 +3 2735 3406 3761 +3 2496 2948 3613 +3 2190 3370 3388 +3 3370 2617 3388 +3 2412 3072 3614 +3 239 238 3635 +3 2480 3241 3417 +3 3241 2749 3417 +3 3236 2772 3506 +3 3653 2556 3701 +3 2255 2996 3753 +3 2525 2990 3469 +3 3026 2462 3644 +3 256 255 3659 +3 285 284 3660 +3 267 266 3673 +3 2415 3166 3626 +3 3023 2409 3411 +3 2186 2967 3561 +3 260 259 3702 +3 281 280 3703 +3 3182 2419 3724 +3 2627 3182 3724 +3 2572 3230 3233 +3 3002 2479 3707 +3 2951 2352 3646 +3 2947 2209 3679 +3 3273 2500 3472 +3 2658 3545 3735 +3 3230 2453 3233 +3 2520 3303 3420 +3 2407 3112 3317 +3 2521 3067 3518 +3 3067 2269 3518 +3 2540 2985 3720 +3 2985 2398 3720 +3 3036 2405 3403 +3 3244 2167 3590 +3 191 3018 3619 +3 2253 2982 3569 +3 2982 2502 3569 +3 3038 2248 3636 +3 2185 3041 3421 +3 3024 2202 3558 +3 2965 2252 3756 +3 2534 2965 3756 +3 2501 3365 3394 +3 2479 3002 3742 +3 2984 2499 3684 +3 3612 2305 3661 +3 3007 2304 3499 +3 3260 2596 3554 +3 2640 3121 3381 +3 3121 2385 3381 +3 3105 2701 3512 +3 3160 2473 3717 +3 3469 2969 3759 +3 2445 2975 3606 +3 2530 3000 3498 +3 2214 3158 3669 +3 3406 2237 3761 +3 2364 3210 3481 +3 3210 2552 3481 +3 3124 2247 3322 +3 2980 2531 3585 +3 3041 2481 3421 +3 3079 2690 3578 +3 3376 2609 3588 +3 2205 3264 3442 +3 3020 2376 3458 +3 2693 2964 3762 +3 2826 3180 3516 +3 2972 2364 3676 +3 2583 3341 3342 +3 3341 2476 3342 +3 3083 2256 3384 +3 3043 2363 3758 +3 3387 2259 3697 +3 2249 2984 3725 +3 2187 3260 3554 +3 173 3116 3349 +3 2610 3272 3561 +3 3272 2186 3561 +3 2490 3368 3466 +3 3107 2164 3413 +3 2497 3107 3413 +3 2609 3376 3446 +3 3376 2193 3446 +3 3075 2471 3407 +3 3026 2209 3479 +3 2506 3363 3636 +3 3052 2609 3446 +3 2283 2977 3712 +3 3150 2412 3614 +3 2558 3043 3758 +3 2994 2507 3592 +3 2545 3436 3622 +3 3334 2206 3757 +3 2245 2994 3592 +3 3402 2604 3415 +3 2349 3402 3415 +3 2443 3165 3338 +3 2470 2979 3748 +3 2416 3016 3576 +3 2419 2983 3724 +3 2368 3037 3475 +3 2605 3286 3538 +3 3286 206 3538 +3 3035 171 3747 +3 2525 3232 3361 +3 3232 2366 3361 +3 2990 2251 3658 +3 2272 3196 3501 +3 3081 2260 3650 +3 3497 2516 3544 +3 2984 2501 3725 +3 2676 3282 3528 +3 3282 2271 3528 +3 2421 3155 3471 +3 3155 2528 3471 +3 2991 2465 3680 +3 3165 2509 3338 +3 2786 3146 3611 +3 2258 3211 3466 +3 3015 2187 3554 +3 3470 2677 3729 +3 2591 3294 3356 +3 3310 2314 3472 +3 2762 3159 3440 +3 3052 2457 3490 +3 2590 3163 3515 +3 2997 2281 3663 +3 2363 2990 3758 +3 2500 3273 3629 +3 3221 2544 3582 +3 3066 2517 3656 +3 3123 251 3399 +3 3045 2277 3500 +3 2508 3119 3535 +3 3096 2524 3546 +3 2342 3096 3546 +3 2251 3574 3621 +3 2526 3226 3587 +3 2529 3257 3529 +3 2414 3090 3516 +3 2194 3072 3467 +3 2316 3033 3533 +3 3000 2530 3718 +3 2380 3000 3718 +3 2318 3002 3707 +3 2260 3081 3616 +3 2721 3088 3679 +3 2705 3509 3535 +3 3509 2508 3535 +3 3425 2636 3492 +3 2514 3425 3492 +3 3146 2396 3611 +3 2640 3381 3547 +3 3381 2527 3547 +3 3035 2510 3552 +3 3101 2205 3442 +3 3017 2342 3605 +3 3138 2781 3568 +3 2699 3021 3659 +3 3021 256 3659 +3 284 3022 3660 +3 3022 2700 3660 +3 3082 2546 3695 +3 2677 3334 3757 +3 2698 3040 3558 +3 3348 2500 3629 +3 3023 2183 3639 +3 2459 3223 3369 +3 2195 3437 3599 +3 3437 2683 3599 +3 3102 2215 3711 +3 2557 3102 3711 +3 3226 2526 3666 +3 2602 3213 3654 +3 3097 222 3493 +3 2420 3082 3695 +3 3496 2588 3527 +3 2408 3134 3693 +3 2289 3119 3470 +3 3119 2508 3470 +3 3187 2325 3438 +3 2683 3268 3571 +3 2517 3066 3549 +3 2531 3097 3493 +3 3129 180 3450 +3 3242 2673 3514 +3 2497 3413 3537 +3 3500 2277 3524 +3 2499 3084 3684 +3 3309 2567 3365 +3 3298 2258 3466 +3 3093 189 3508 +3 3090 2492 3516 +3 2644 3497 3544 +3 2382 3236 3506 +3 2583 3067 3581 +3 2381 3380 3447 +3 3159 2401 3440 +3 183 3070 3577 +3 2463 3204 3400 +3 3443 2539 3694 +3 2570 3298 3466 +3 3035 2675 3704 +3 3062 2505 3700 +3 3031 2555 3754 +3 2662 3058 3625 +3 2228 3115 3503 +3 2300 3439 3653 +3 2644 3603 3715 +3 2474 3085 3579 +3 2675 3035 3747 +3 2505 3367 3664 +3 2557 3647 3652 +3 3231 2346 3434 +3 2560 3231 3434 +3 3102 2557 3760 +3 2382 3102 3760 +3 3240 2702 3712 +3 2240 3385 3682 +3 3385 2678 3682 +3 3334 2677 3470 +3 3389 2607 3510 +3 2555 3389 3510 +3 2478 3143 3489 +3 2777 3284 3377 +3 3284 2208 3377 +3 3574 2684 3621 +3 3180 2414 3516 +3 2514 3187 3438 +3 2549 3449 3559 +3 3449 2656 3559 +3 2562 3312 3476 +3 3312 263 3476 +3 3097 2531 3627 +3 2456 3097 3627 +3 3291 2547 3620 +3 2804 3291 3620 +3 2598 3398 3699 +3 3081 2489 3616 +3 3216 2267 3716 +3 2593 3216 3716 +3 2469 3125 3527 +3 3412 2653 3708 +3 2248 3254 3636 +3 3294 2484 3356 +3 3095 2252 3591 +3 2289 3470 3729 +3 2188 3166 3496 +3 3349 2675 3747 +3 172 3349 3747 +3 3164 2504 3761 +3 2179 3431 3587 +3 3341 2583 3523 +3 2242 3341 3523 +3 2486 3256 3621 +3 2296 3309 3365 +3 2296 3084 3681 +3 3084 2296 3684 +3 3274 2516 3497 +3 2749 3239 3439 +3 3239 2511 3439 +3 2544 3514 3582 +3 2619 3396 3522 +3 3396 2551 3522 +3 2922 3120 3710 +3 3120 2171 3710 +3 3211 2490 3466 +3 2539 3528 3694 +3 2236 3302 3738 +3 3182 2214 3505 +3 3406 2620 3564 +3 2237 3406 3564 +3 2395 3138 3568 +3 2693 3110 3633 +3 2209 3311 3479 +3 3311 2728 3479 +3 3196 2272 3544 +3 3098 2870 3697 +3 3385 2482 3386 +3 2678 3385 3386 +3 3178 2538 3755 +3 3495 2283 3643 +3 2696 3125 3617 +3 3196 2485 3501 +3 2573 3576 3691 +3 2270 3139 3664 +3 2652 3374 3698 +3 3374 2197 3698 +3 2473 3302 3685 +3 2238 3152 3631 +3 3113 2730 3668 +3 2470 3237 3690 +3 3113 2236 3738 +3 2644 3354 3603 +3 3354 2341 3603 +3 3257 2582 3673 +3 266 3257 3673 +3 3190 2492 3593 +3 3326 2658 3735 +3 2450 3326 3735 +3 2634 3150 3614 +3 2517 3263 3656 +3 3315 2408 3693 +3 2398 3113 3720 +3 3256 2251 3621 +3 2516 3196 3544 +3 3375 2486 3621 +3 3402 2349 3750 +3 2726 3402 3750 +3 3174 2238 3631 +3 2260 3329 3650 +3 3335 2739 3714 +3 2618 3335 3714 +3 3139 2815 3664 +3 2406 3117 3731 +3 2191 3378 3462 +3 3378 2556 3462 +3 3237 2250 3547 +3 3134 2489 3693 +3 3166 2708 3626 +3 151 3345 3455 +3 2485 3373 3501 +3 3373 2590 3501 +3 2832 3321 3648 +3 2850 3315 3693 +3 2544 3242 3514 +3 3507 2659 3709 +3 2751 3261 3499 +3 3246 2573 3692 +3 2309 3246 3692 +3 2524 3174 3631 +3 2866 3303 3548 +3 3157 2420 3695 +3 3222 2597 3562 +3 2189 3274 3497 +3 3537 2344 3727 +3 2723 3537 3727 +3 2500 3310 3472 +3 2527 3237 3547 +3 3193 2518 3683 +3 3345 2535 3455 +3 2665 3221 3582 +3 2190 3160 3717 +3 2449 3231 3677 +3 3231 2560 3677 +3 3380 2744 3447 +3 2566 3262 3665 +3 3262 2278 3665 +3 2508 3334 3470 +3 3360 2529 3745 +3 2454 3235 3648 +3 2980 3362 3627 +3 2710 3531 3688 +3 3531 2569 3688 +3 2548 3340 3730 +3 2237 3164 3761 +3 3304 2372 3572 +3 2678 3304 3572 +3 3170 2450 3735 +3 2267 3216 3628 +3 3216 2543 3628 +3 3195 2556 3653 +3 2284 3245 3651 +3 3245 2553 3651 +3 2533 3275 3550 +3 3217 2439 3633 +3 3214 2435 3652 +3 3497 2644 3715 +3 3603 2600 3715 +3 3179 2603 3752 +3 3225 2522 3624 +3 3327 2416 3576 +3 2196 3478 3752 +3 3303 2520 3548 +3 3477 2507 3478 +3 2717 3477 3478 +3 3235 2532 3648 +3 3495 2606 3543 +3 2565 3495 3543 +3 3243 2267 3628 +3 2500 3348 3521 +3 2839 3312 3618 +3 2603 3689 3752 +3 2551 3208 3734 +3 3542 2614 3722 +3 3254 2506 3636 +3 2467 3259 3689 +3 2526 3431 3662 +3 3601 2699 3659 +3 255 3601 3659 +3 2700 3600 3660 +3 3600 285 3660 +3 2529 3513 3745 +3 3321 2454 3648 +3 3237 2527 3690 +3 3232 2525 3759 +3 187 3449 3696 +3 2573 3327 3576 +3 2284 3494 3704 +3 3273 2725 3629 +3 3290 2522 3612 +3 3263 2285 3656 +3 3353 2253 3569 +3 3370 2190 3625 +3 2653 3610 3661 +3 3277 2276 3654 +3 2653 3412 3610 +3 2167 3394 3590 +3 3394 2567 3590 +3 3444 146 3536 +3 2569 3444 3536 +3 3270 2185 3675 +3 3312 2562 3618 +3 3250 2380 3718 +3 3572 2597 3682 +3 2846 3246 3732 +3 3246 2309 3732 +3 2678 3572 3682 +3 3296 2578 3749 +3 2458 3296 3749 +3 2762 3494 3651 +3 3283 2473 3685 +3 3318 2467 3689 +3 2306 3348 3629 +3 2567 3309 3643 +3 2534 3376 3588 +3 3367 2270 3664 +3 3329 2738 3650 +3 3461 2320 3670 +3 2668 3461 3670 +3 2271 3492 3694 +3 3492 2636 3694 +3 3362 2456 3627 +3 2684 3375 3621 +3 2603 3318 3689 +3 3352 2307 3751 +3 2587 3352 3751 +3 3431 2526 3587 +3 3610 2612 3661 +3 3412 2304 3610 +3 3421 2481 3634 +3 2636 3443 3694 +3 3514 2282 3582 +3 3608 2347 3736 +3 2695 3608 3736 +3 2541 3463 3731 +3 3314 2534 3756 +3 2669 3421 3634 +3 3391 2249 3666 +3 2257 3360 3745 +3 3378 2585 3701 +3 3562 2597 3572 +3 2496 3387 3697 +3 3461 2615 3722 +3 2320 3461 3722 +3 2579 3505 3669 +3 2372 3562 3572 +3 2165 3550 3706 +3 3649 2704 3732 +3 2309 3649 3732 +3 3545 2658 3744 +3 2203 3545 3744 +3 2578 3412 3708 +3 3494 2284 3651 +3 2357 3595 3641 +3 3595 2632 3641 +3 3449 2549 3696 +3 2300 3653 3701 +3 3563 2289 3729 +3 2647 3563 3729 +3 2525 3469 3759 +3 2203 3452 3728 +3 3452 2595 3728 +3 3505 2214 3669 +3 2812 3647 3711 +3 2677 3630 3729 +3 3630 2647 3729 +3 2573 3691 3692 +3 3691 2733 3692 +3 2771 3677 3678 +3 3677 2560 3678 +3 2189 3497 3715 +3 2571 3507 3709 +3 3528 2271 3694 +3 3625 2190 3717 +3 2662 3625 3717 +3 3740 2822 3741 +3 2561 3740 3741 +3 3513 2776 3745 +3 2615 3542 3722 +3 3670 2651 3721 +3 2668 3670 3721 +3 2938 3706 3730 +3 3615 2867 3749 +3 2578 3615 3749 +3 3647 2557 3711 +3 3720 3113 3738 +3 2990 3658 3758 +3 3658 2558 3758 +3 3706 2548 3730 +3 2540 3720 3738 +3 130 4230 131 +3 4314 4487 3835 +3 4018 4487 4314 +3 4214 4763 3850 +3 4052 4763 4214 +3 3883 4752 4267 +3 4187 4515 317 +3 4029 4473 4361 +3 4172 4466 3926 +3 4079 4803 4672 +3 4832 4840 3782 +3 115 4986 4823 +3 3772 4782 4256 +3 4137 4760 4024 +3 4142 4747 4715 +3 3905 4454 4341 +3 4128 4752 4385 +3 4385 4752 3883 +3 4365 4485 4068 +3 3932 4485 4365 +3 3862 4558 4202 +3 4024 5260 4137 +3 4792 4977 4336 +3 4191 4382 3910 +3 3857 4437 4163 +3 4159 4797 4034 +3 3780 4608 4588 +3 4267 4752 4734 +3 3809 4392 4331 +3 4350 4468 3968 +3 3862 4480 4147 +3 3778 4381 4170 +3 4361 4473 3763 +3 4234 4618 301 +3 4231 4741 3943 +3 3819 4514 4414 +3 4213 4511 3794 +3 4715 4747 4007 +3 3859 4379 4174 +3 4302 4358 3948 +3 3934 4358 4302 +3 4208 4992 123 +3 3902 4985 4300 +3 4205 4920 4896 +3 4374 4505 4047 +3 3779 4505 4374 +3 4347 4348 4065 +3 3893 4348 4347 +3 4300 4985 4958 +3 4193 4349 3772 +3 4378 4608 3780 +3 4176 4529 143 +3 4592 5009 3900 +3 3900 5009 4357 +3 3935 4889 4206 +3 4265 5278 3956 +3 3956 5278 4264 +3 3960 4432 4394 +3 4179 4703 3869 +3 3868 4702 4180 +3 3814 4472 4287 +3 4303 4422 3808 +3 3969 4422 4303 +3 3963 4598 4248 +3 4315 4316 4014 +3 3894 4316 4315 +3 4107 4624 4352 +3 4005 4407 4239 +3 4205 4896 3798 +3 4297 4508 4028 +3 3848 4508 4297 +3 4256 5247 3927 +3 3927 5247 4255 +3 3772 5016 4193 +3 3936 4445 4252 +3 3895 4656 4289 +3 4060 4576 4540 +3 4126 4840 4832 +3 3986 4580 4550 +3 4550 4580 4137 +3 4514 4913 4414 +3 3818 4607 4259 +3 4879 5017 4157 +3 4842 4986 254 +3 4169 4663 3796 +3 4147 4558 3862 +3 3790 4665 4299 +3 4224 4447 3933 +3 3765 4531 4376 +3 4376 4531 4051 +3 4303 4949 4826 +3 4411 5102 339 +3 4244 4363 3993 +3 3992 4362 4245 +3 3821 4645 4273 +3 4273 4645 4041 +3 4070 4601 4380 +3 4380 4601 3868 +3 3926 4863 4172 +3 4195 4770 4039 +3 3840 4770 4195 +3 4051 5288 4209 +3 4352 5276 4107 +3 3824 4799 4162 +3 3911 4666 4338 +3 4516 4629 3827 +3 3796 4847 4169 +3 128 4295 129 +3 4247 4862 3775 +3 4779 5189 3835 +3 4303 4826 3891 +3 115 4823 116 +3 4047 4750 4418 +3 3815 4382 4191 +3 336 4831 4237 +3 219 4761 4338 +3 3780 4588 4342 +3 123 4992 124 +3 4256 4782 4455 +3 3865 4745 4161 +3 4558 4716 4202 +3 3782 4547 4359 +3 4359 4547 4049 +3 3871 4642 4167 +3 3949 4399 4194 +3 4809 4999 244 +3 4298 4381 4010 +3 4043 4835 4186 +3 4191 4392 3920 +3 353 4621 4244 +3 4245 4622 327 +3 3827 4629 4375 +3 3938 5022 4160 +3 4157 5312 3765 +3 250 4669 4291 +3 4209 5288 4448 +3 3835 5189 4405 +3 4187 4405 3913 +3 3921 4393 4218 +3 4218 4393 3773 +3 3925 4390 4196 +3 4424 5306 4893 +3 4044 4721 4260 +3 4491 5111 5067 +3 4330 4572 4064 +3 3869 4572 4330 +3 3834 4649 4369 +3 4369 4649 4075 +3 4456 4654 3957 +3 4116 4654 4456 +3 4419 4742 3924 +3 3825 4522 4153 +3 4249 4687 3797 +3 125 4992 4156 +3 340 4411 339 +3 3765 4978 4157 +3 3905 4632 4309 +3 3924 4742 4668 +3 3939 5111 4491 +3 219 4338 220 +3 4010 4674 4211 +3 3768 4416 4197 +3 4197 4416 3918 +3 4264 4413 3813 +3 4619 4838 305 +3 3951 4538 4290 +3 4893 5306 3863 +3 4236 4703 3995 +3 3994 4702 4235 +3 4468 4581 3968 +3 4081 4740 4326 +3 4326 4740 3944 +3 317 4825 4187 +3 3806 4560 4289 +3 4230 4499 131 +3 4355 4741 4231 +3 4226 4768 4045 +3 3787 4768 4226 +3 4352 4624 3996 +3 4258 4571 3828 +3 4153 4597 3825 +3 4199 4920 3873 +3 4069 4920 4199 +3 4160 4551 3938 +3 3896 4771 4311 +3 4311 4771 4082 +3 3913 4515 4187 +3 128 4900 4295 +3 4005 4525 4407 +3 3989 4577 4155 +3 3928 4446 4412 +3 4412 4446 4030 +3 4155 4625 3989 +3 4454 4756 4341 +3 4034 5188 4159 +3 4260 4721 3841 +3 4156 4631 125 +3 310 4857 4280 +3 4182 4513 3883 +3 286 4796 4305 +3 3995 4739 4236 +3 4418 4750 4098 +3 4373 4626 4064 +3 3951 4626 4373 +3 3804 4433 4420 +3 4420 4433 4023 +3 3911 5196 4666 +3 4171 4484 3917 +3 3847 4595 4497 +3 4497 4595 4108 +3 4341 4632 3905 +3 4346 4502 3915 +3 4245 4362 3930 +3 3931 4363 4244 +3 4152 4999 4809 +3 4392 4854 4331 +3 3966 4596 4254 +3 4161 4682 3865 +3 4198 5055 3922 +3 4661 5176 4164 +3 234 5173 4421 +3 4073 5017 4879 +3 4294 4337 3912 +3 253 4842 254 +3 4163 4534 3857 +3 4607 5146 4259 +3 4174 4562 3859 +3 3923 4712 4408 +3 3983 4572 4236 +3 4236 4572 3869 +3 3844 4371 4309 +3 4219 4942 4080 +3 3872 4942 4219 +3 4511 5033 3794 +3 3883 4635 4182 +3 4162 5053 3824 +3 4896 4920 4069 +3 4178 5115 4537 +3 4427 4581 4072 +3 3968 4581 4427 +3 4224 5238 4447 +3 4167 4718 3871 +3 4289 4656 4537 +3 3852 4736 4246 +3 3946 5034 4220 +3 4357 4781 4731 +3 4628 5157 241 +3 4588 5028 4342 +3 3917 4777 4171 +3 4333 4834 4054 +3 4206 4515 3913 +3 4424 4893 4130 +3 246 4999 4222 +3 4537 5124 4178 +3 3970 4565 4184 +3 3790 4947 4665 +3 4235 4737 3994 +3 3772 4440 4212 +3 4045 4872 4226 +3 4247 5177 4862 +3 3900 5301 4298 +3 4674 5099 4211 +3 3918 4815 4197 +3 4274 5156 4154 +3 3887 5156 4274 +3 3913 5002 4206 +3 4336 4977 3895 +3 4624 4851 4383 +3 4657 4712 3923 +3 241 5157 242 +3 4482 4889 3935 +3 3800 4412 4312 +3 4312 4412 4030 +3 4384 4489 4028 +3 3958 4489 4384 +3 3841 4530 4260 +3 4260 4530 3977 +3 3988 4406 4387 +3 4387 4406 3778 +3 4217 5065 3773 +3 4835 4896 4186 +3 4164 5077 4661 +3 4285 4456 3774 +3 4052 4744 4374 +3 4298 5301 4381 +3 3922 4536 4198 +3 3791 4460 4283 +3 4356 4538 3951 +3 4397 4996 3957 +3 3920 4767 4191 +3 3920 4440 4349 +3 4397 5071 4996 +3 4360 4432 3960 +3 4193 5016 3927 +3 4317 4796 288 +3 4170 4953 3954 +3 4329 4639 3964 +3 4189 4667 4659 +3 4333 5025 4834 +3 4229 4442 3976 +3 4057 4442 4229 +3 3996 4624 4383 +3 3804 4409 4255 +3 4255 4409 3927 +3 3954 4693 4170 +3 4310 4981 3775 +3 4354 4410 3944 +3 4293 4532 3915 +3 4170 4693 3778 +3 3797 5145 4249 +3 4271 4865 3807 +3 3813 4474 4264 +3 4264 4474 3956 +3 3980 4439 4342 +3 4189 4706 3809 +3 3998 4706 4189 +3 4195 4897 3840 +3 3924 4403 4259 +3 4259 4403 3818 +3 4540 4576 3973 +3 3770 4564 4398 +3 4450 4775 3937 +3 4357 5171 3839 +3 4223 5171 4357 +3 4342 4439 3780 +3 4897 5011 4492 +3 4775 5183 3937 +3 4274 5296 4415 +3 5055 5333 3805 +3 4435 4451 3971 +3 4177 4994 3956 +3 313 4677 312 +3 4202 4541 3862 +3 3950 4541 4202 +3 313 5197 4677 +3 3872 4710 4325 +3 3903 5332 4188 +3 3859 4562 4189 +3 4227 4528 3803 +3 3959 4528 4227 +3 301 4618 300 +3 4415 5296 3812 +3 3840 4897 4492 +3 3956 4928 4177 +3 3894 4691 4316 +3 3850 4664 4214 +3 287 4796 286 +3 143 5067 4176 +3 3848 5099 4674 +3 4199 4480 4069 +3 3820 4717 4238 +3 4381 5167 4010 +3 4197 4888 3768 +3 3882 4568 4178 +3 4196 4486 3925 +3 4001 4458 4375 +3 4375 4458 3960 +3 4235 4601 3982 +3 3868 4601 4235 +3 3933 4436 4224 +3 311 4857 310 +3 4246 5153 3852 +3 4300 5337 3902 +3 3902 5337 4299 +3 337 4831 336 +3 3927 4791 4193 +3 4112 4838 4619 +3 3784 4429 4231 +3 249 4669 250 +3 4357 4731 3900 +3 4555 4683 4034 +3 4148 4683 4555 +3 3915 4532 4314 +3 4189 4659 3859 +3 3944 4387 4326 +3 4326 4387 3778 +3 4178 4600 3882 +3 4806 4981 4310 +3 4325 4860 3872 +3 4500 5134 4673 +3 3779 4724 4401 +3 3938 4499 4230 +3 4721 5174 4503 +3 4598 4784 4248 +3 3794 5285 4213 +3 4063 4736 4334 +3 4334 4736 3852 +3 4472 5107 4287 +3 3918 4559 4182 +3 4068 4389 4295 +3 117 4823 4268 +3 4277 4842 252 +3 4394 4432 3823 +3 3951 4373 4356 +3 4356 4373 3776 +3 4190 4798 4793 +3 3869 4751 4179 +3 4309 4371 3980 +3 3878 4542 4192 +3 4403 4404 3983 +3 3924 4404 4403 +3 4090 4977 4792 +3 4811 5242 4182 +3 4659 4667 3970 +3 4180 4820 3868 +3 3817 4441 4308 +3 3881 4863 4210 +3 4192 4520 3878 +3 4206 5002 3935 +3 4157 5017 4533 +3 3769 4997 4407 +3 4407 4997 4173 +3 3764 4787 4569 +3 4228 4555 3788 +3 4080 4991 4219 +3 4215 4620 3807 +3 3978 4620 4215 +3 4569 5265 3764 +3 4304 4586 3947 +3 4005 4586 4304 +3 234 4421 235 +3 4209 5230 3949 +3 4398 4564 4062 +3 3766 4476 4313 +3 4313 4476 4033 +3 4102 4630 4498 +3 4498 4630 3999 +3 3920 5076 4440 +3 4320 4476 3766 +3 3975 4476 4320 +3 4186 4813 4043 +3 4287 4399 3814 +3 4295 4389 3916 +3 4263 4771 3896 +3 217 4368 218 +3 3899 5291 4207 +3 4023 4509 4420 +3 4182 4635 3918 +3 4793 4798 4020 +3 4363 4523 3811 +3 4283 4589 3791 +3 4408 4803 4079 +3 3978 4682 4609 +3 4207 4909 3899 +3 4348 4882 4066 +3 4189 4562 3998 +3 4301 5200 3898 +3 4166 5200 4301 +3 4194 4988 3949 +3 4421 5173 4172 +3 4226 4475 3877 +3 3962 4388 4372 +3 4372 4388 3832 +3 3800 5041 4412 +3 4823 4986 4145 +3 4407 4525 3769 +3 5027 5041 3800 +3 288 4796 287 +3 4672 4803 4037 +3 3779 5094 4724 +3 4227 5004 3959 +3 3959 5004 4228 +3 4387 4449 3988 +3 4184 4659 3970 +3 4362 4549 3930 +3 3805 5333 4438 +3 4271 5087 4865 +3 3773 4594 4217 +3 4230 5180 3938 +3 4559 4811 4182 +3 3964 4639 4465 +3 4364 4585 3837 +3 4035 4585 4364 +3 3861 5038 5030 +3 3873 4570 4199 +3 3970 5042 4877 +3 4191 4767 3815 +3 4339 5038 3861 +3 4188 4723 3903 +3 3916 4650 4295 +3 3910 4854 4191 +3 4084 4925 4706 +3 4609 4682 4161 +3 4039 4589 4195 +3 3927 5016 4256 +3 3906 5338 4238 +3 323 4311 322 +3 3841 4721 4503 +3 3879 4640 4204 +3 3947 4544 4481 +3 4224 5227 4040 +3 4084 4706 4507 +3 4334 4730 3936 +3 4254 4891 3966 +3 3809 4667 4189 +3 4395 4703 4179 +3 4180 4702 4396 +3 4537 5115 3806 +3 4687 5040 3797 +3 3949 4670 4209 +3 5065 5314 3773 +3 4500 4673 3837 +3 3971 4451 4394 +3 5055 5280 3922 +3 3869 4703 4236 +3 4235 4702 3868 +3 3898 4418 4301 +3 4202 4849 3950 +3 4314 5005 3915 +3 3836 4874 4389 +3 3788 4566 4228 +3 4228 4566 3959 +3 4560 4946 4289 +3 4338 4761 4046 +3 4549 5075 3930 +3 4011 5052 4276 +3 4267 4635 3883 +3 3916 5180 4650 +3 4691 5047 4316 +3 4502 5054 3915 +3 4410 4449 3944 +3 4874 5072 4389 +3 3972 4971 4662 +3 4204 4814 3879 +3 4295 4900 4068 +3 3968 4427 4367 +3 4367 4427 3820 +3 3967 5124 4537 +3 4060 4540 4353 +3 4312 4845 4053 +3 3985 4564 4423 +3 4221 4585 4035 +3 3832 4536 4216 +3 3935 5002 4249 +3 3791 5243 4460 +3 354 4621 353 +3 327 4622 326 +3 3922 5325 4536 +3 3962 4391 4388 +3 4388 4391 3941 +3 4343 4759 3763 +3 4066 4759 4343 +3 4240 4512 3942 +3 3796 4512 4240 +3 4008 4538 4356 +3 4536 5325 4216 +3 4212 4634 3969 +3 3928 4724 4446 +3 4825 5082 4187 +3 338 4831 337 +3 4337 4478 3812 +3 3771 4849 4716 +3 4599 4831 338 +3 4211 4567 4029 +3 4461 4652 4016 +3 3936 4730 4370 +3 4469 5034 3946 +3 317 4515 316 +3 4374 4744 3779 +3 4046 4688 4338 +3 4338 4688 3911 +3 4243 4501 3876 +3 4290 5259 3951 +3 4248 4784 3957 +3 4716 4849 4202 +3 3877 4611 4226 +3 4285 4580 3986 +3 3774 4580 4285 +3 4131 5102 4411 +3 4736 5220 4246 +3 3976 4641 4229 +3 4229 4641 3803 +3 4027 4493 4251 +3 4208 4707 4000 +3 3799 5223 4296 +3 4296 5223 4154 +3 3896 5297 4529 +3 4424 4797 4159 +3 3985 5086 4205 +3 4205 4772 3985 +3 3933 4872 4436 +3 4196 5222 4660 +3 4445 5106 4252 +3 3991 4552 4535 +3 4535 4552 4078 +3 3930 4622 4245 +3 4244 4621 3931 +3 4398 4691 3894 +3 4062 4691 4398 +3 4017 4506 4296 +3 4486 5215 333 +3 3798 5334 4205 +3 4677 4857 312 +3 4664 5006 4214 +3 4238 5209 3820 +3 4136 4929 4534 +3 4145 4986 4842 +3 217 4993 4368 +3 4029 4799 4211 +3 4285 5024 4456 +3 3937 4868 4241 +3 4398 5079 3770 +3 4242 4868 3937 +3 4529 5313 3896 +3 4352 4522 3825 +3 3996 4522 4352 +3 4350 4410 3945 +3 3829 4410 4350 +3 3914 4680 4379 +3 4282 4522 3996 +3 4252 4851 3858 +3 4048 4851 4252 +3 4004 4709 4222 +3 245 4999 246 +3 4575 4941 4185 +3 4210 4653 3881 +3 4240 4954 3875 +3 3789 5303 4861 +3 3875 4526 4240 +3 4209 4919 4051 +3 4000 4769 4208 +3 4251 4506 3885 +3 4252 4685 3936 +3 4317 4523 3931 +3 4011 4523 4317 +3 4223 4603 4001 +3 123 4707 4208 +3 3930 4993 4306 +3 4746 5005 4314 +3 3940 5011 4473 +3 3803 5074 4229 +3 4222 4762 4004 +3 3888 5278 4493 +3 4467 4576 4060 +3 3822 4576 4467 +3 4279 4952 4017 +3 4473 5011 4951 +3 3865 4682 4215 +3 4215 4682 3978 +3 4322 5240 3866 +3 4061 5082 4825 +3 3945 4410 4354 +3 4248 5317 3963 +3 4216 5014 3832 +3 4241 4705 3937 +3 135 4336 136 +3 4319 4431 4025 +3 3963 4431 4319 +3 4349 4440 3772 +3 4233 4578 3943 +3 3943 4738 4231 +3 3969 4782 4212 +3 4445 4524 3830 +3 4038 4524 4445 +3 4283 4460 3979 +3 3891 4455 4303 +3 3767 4561 4370 +3 3955 4716 4558 +3 4212 4782 3772 +3 4215 5267 3865 +3 4436 4872 4780 +3 4211 4694 4010 +3 4226 4872 4475 +3 3807 5031 4215 +3 3817 4800 4386 +3 4233 4741 3816 +3 4179 4751 4554 +3 312 4857 311 +3 4245 4935 3992 +3 3993 4934 4244 +3 4226 4931 3787 +3 4181 5285 4726 +3 3942 4954 4240 +3 3878 4520 4275 +3 4275 4520 4015 +3 4308 4441 3923 +3 4724 4924 4446 +3 3844 4941 4575 +3 4042 5101 4297 +3 3843 4671 4302 +3 4932 4989 4527 +3 4238 4717 3906 +3 3771 4614 4225 +3 4220 4644 3946 +3 4225 4849 3771 +3 4198 5333 5055 +3 4303 4455 3969 +3 4214 4744 4052 +3 4297 5250 4042 +3 4313 4470 3766 +3 3953 4470 4313 +3 4224 4676 293 +3 4527 4989 3842 +3 301 4829 4234 +3 3970 4877 4565 +3 3937 5183 4242 +3 4035 5100 4221 +3 4268 4713 117 +3 3947 4481 4304 +3 4304 4481 3826 +3 3775 4981 4247 +3 4218 5020 3921 +3 4278 4732 3876 +3 320 4346 319 +3 331 4395 330 +3 350 4396 349 +3 4650 5180 4230 +3 3798 4896 4835 +3 4432 4586 3823 +3 3773 4719 4218 +3 4151 5079 4398 +3 4037 4735 4679 +3 4402 4441 3982 +3 3923 4441 4402 +3 4219 4710 3872 +3 4066 5001 4348 +3 4083 4512 4453 +3 4453 4512 3796 +3 4001 5171 4223 +3 4261 5051 297 +3 3827 4451 4435 +3 4212 4917 4634 +3 4652 4940 4016 +3 4222 4709 246 +3 4040 4676 4224 +3 4493 5278 4265 +3 3803 4641 4227 +3 4234 4598 3963 +3 4026 4745 4364 +3 3806 4747 4560 +3 4560 4747 4142 +3 4229 4841 4057 +3 4144 5185 4307 +3 4307 5185 3793 +3 4355 5338 3906 +3 4231 5338 4355 +3 3775 4540 4310 +3 4310 4540 3973 +3 126 4365 127 +3 4634 4917 3864 +3 293 5238 4224 +3 4314 5261 4018 +3 3956 5193 4265 +3 4570 4971 3972 +3 5067 5111 4176 +3 4571 4894 3828 +3 4312 5192 4845 +3 3938 5180 4324 +3 130 4650 4230 +3 3968 4479 4350 +3 4350 4479 3829 +3 4324 5022 3938 +3 4481 4544 4032 +3 3821 4654 4645 +3 304 4351 303 +3 3963 4618 4234 +3 4239 5184 5123 +3 4427 5073 3820 +3 4370 4730 4072 +3 4256 5016 3772 +3 4554 4751 3992 +3 4596 4929 4254 +3 252 4842 253 +3 3856 4905 4578 +3 4726 5229 4181 +3 4297 4490 3848 +3 4347 4797 3893 +3 4260 4881 4044 +3 4306 4993 216 +3 4311 5297 3896 +3 4002 5146 4607 +3 4404 4927 3776 +3 4427 5298 5073 +3 4766 4871 3847 +3 4844 5012 4092 +3 4019 5059 4233 +3 4319 4618 3963 +3 3947 4432 4360 +3 4236 5117 3983 +3 4488 5240 4322 +3 3786 4801 4457 +3 4023 4781 4509 +3 3784 4489 4429 +3 4460 5243 4203 +3 3911 5259 4290 +3 3982 5061 4235 +3 4247 4610 3879 +3 4368 4993 3930 +3 297 4695 4261 +3 3765 5312 4625 +3 4233 4811 4019 +3 3816 4811 4233 +3 4273 4611 3877 +3 3977 4783 4655 +3 116 4823 117 +3 252 4722 4277 +3 4391 4727 3941 +3 4464 4826 3954 +3 4088 4956 4343 +3 244 4999 245 +3 4237 4831 3981 +3 4305 4796 3931 +3 3912 5204 4294 +3 4569 4787 4095 +3 224 4901 4340 +3 4231 4738 3784 +3 4142 4715 4437 +3 4495 4984 3781 +3 4010 4694 4298 +3 4298 4694 3824 +3 4266 4644 3897 +3 4237 4830 336 +3 4829 4936 4234 +3 4027 5003 4291 +3 4086 4936 4829 +3 4097 4613 4557 +3 4557 4613 3972 +3 4292 4646 4093 +3 3981 4729 4237 +3 4948 5013 4327 +3 4320 4633 3975 +3 4240 4847 3796 +3 3943 4741 4233 +3 3976 4442 4417 +3 4417 4442 3851 +3 4154 4836 4274 +3 318 4825 317 +3 4333 4462 3919 +3 4645 4654 4116 +3 4495 5198 4984 +3 4260 4655 3874 +3 3977 4655 4260 +3 3780 4459 4378 +3 3961 4960 4870 +3 4728 5052 4011 +3 143 4529 144 +3 4272 5314 5065 +3 334 4486 333 +3 4289 5175 3895 +3 3893 4882 4348 +3 3957 4654 4248 +3 3932 5069 4485 +3 4309 4632 3844 +3 4306 4622 3930 +3 3931 4621 4305 +3 4188 5332 4617 +3 4382 5239 3910 +3 4196 5215 4486 +3 3896 5313 4263 +3 4395 5309 330 +3 350 5308 4396 +3 4374 4926 4052 +3 4461 4474 3813 +3 4016 4474 4461 +3 4155 5010 4899 +3 3866 4916 4322 +3 4322 4916 4085 +3 4238 5338 4429 +3 4239 5021 4005 +3 4954 5149 3875 +3 4459 4483 4003 +3 3883 4513 4385 +3 4254 4944 139 +3 4534 4929 3857 +3 4995 5069 3932 +3 4244 4934 353 +3 327 4935 4245 +3 3990 5006 4664 +3 4343 4951 4088 +3 3876 4732 4243 +3 4360 4544 3947 +3 4457 4801 4092 +3 3965 4574 4284 +3 4284 4574 3811 +3 4259 4957 3924 +3 4169 5203 4663 +3 4328 4662 3909 +3 4524 4735 4037 +3 3931 4796 4317 +3 4020 4488 4322 +3 3828 4692 4258 +3 216 5213 4306 +3 4305 5212 286 +3 3879 5177 4247 +3 3981 4697 4269 +3 3801 4532 4293 +3 4378 4459 4003 +3 4276 4743 4011 +3 4948 4990 4593 +3 3788 4593 4566 +3 4566 4593 4087 +3 4301 4846 4166 +3 4065 5013 4948 +3 4289 4537 3806 +3 4456 4996 3774 +3 4360 4458 3783 +3 3960 4458 4360 +3 3945 4468 4350 +3 4290 4538 3834 +3 4697 4807 4269 +3 4299 4665 3902 +3 4826 4945 3954 +3 3858 4685 4252 +3 4564 5228 4423 +3 3875 4795 4426 +3 4426 4795 4089 +3 4386 4800 4680 +3 4323 5259 3911 +3 4745 5036 4364 +3 3874 4881 4260 +3 236 4890 4496 +3 3960 4451 4375 +3 3949 5230 4399 +3 4497 4637 3847 +3 4074 4637 4497 +3 4593 4990 4087 +3 4030 4675 4543 +3 4543 4675 4100 +3 3994 5176 4661 +3 320 4502 4346 +3 4325 4710 4008 +3 3801 5130 4602 +3 4680 5142 4379 +3 3971 4483 4459 +3 4092 5012 4457 +3 4249 4786 3935 +3 4025 4822 4261 +3 4301 4970 3797 +3 4255 5126 3804 +3 3891 5247 4455 +3 4375 4451 3827 +3 3885 4833 4251 +3 4251 4833 4027 +3 4252 5106 4048 +3 4426 4526 3875 +3 4013 4526 4426 +3 3944 4449 4387 +3 4154 5156 4296 +3 4257 5280 5055 +3 4455 5247 4256 +3 3975 4516 4476 +3 4476 4516 4033 +3 4753 5303 3789 +3 4449 4627 3988 +3 4660 5215 4196 +3 4523 4757 3811 +3 4293 5130 3801 +3 3795 5148 4444 +3 4444 5148 4207 +3 4541 4930 3862 +3 4186 4930 4541 +3 3897 4658 4266 +3 4302 4605 3843 +3 4615 4681 4059 +3 4668 4927 4404 +3 288 4728 4317 +3 4041 4611 4273 +3 3807 4620 4271 +3 4008 4649 4538 +3 4100 4888 4543 +3 3979 5108 4283 +3 4578 4905 4125 +3 4532 5261 4314 +3 3936 4685 4334 +3 4394 4451 3960 +3 4602 5130 4263 +3 4261 4695 4025 +3 3804 4907 4409 +3 4409 4907 4109 +3 4433 5126 3954 +3 4996 5143 3774 +3 3890 4806 4310 +3 4290 5196 3911 +3 4354 4740 3808 +3 4336 5175 4121 +3 3810 4626 4323 +3 139 4891 4254 +3 4553 4820 4180 +3 4826 4949 4081 +3 3974 4955 4913 +3 4343 4956 3892 +3 3972 4613 4570 +3 4050 5088 4860 +3 5006 5094 4214 +3 4161 4745 4428 +3 4586 5021 3823 +3 4207 5291 4444 +3 4716 5274 3771 +3 3834 4582 4290 +3 4960 5168 4183 +3 4294 5340 4337 +3 4407 5184 4239 +3 4730 4837 4072 +3 4294 5274 4716 +3 4698 4856 4167 +3 4550 4717 3820 +3 4050 4860 4325 +3 4367 4479 3968 +3 4884 4907 3952 +3 3808 4816 4354 +3 4435 4439 3980 +3 3829 5330 4384 +3 4888 5302 4543 +3 4358 4714 3948 +3 3918 5138 4815 +3 3766 4850 4785 +3 3961 4531 4318 +3 4414 4867 4113 +3 3954 5126 4464 +3 3910 5234 4331 +3 4331 5234 4149 +3 239 4428 240 +3 5119 5214 3965 +3 4456 5024 4116 +3 4439 4459 3780 +3 3829 4449 4410 +3 4335 5193 3956 +3 4573 4652 4015 +3 3797 5282 4301 +3 4394 4483 3971 +3 3823 4483 4394 +3 3836 4557 4328 +3 4328 4557 3972 +3 3847 4871 4595 +3 4297 5101 4490 +3 4307 4556 4053 +3 4309 5218 3905 +3 3815 4807 4697 +3 4162 4893 4878 +3 4033 4828 4313 +3 4269 4798 3861 +3 4020 4798 4269 +3 4376 4978 3765 +3 3901 4899 4497 +3 4388 4805 3832 +3 4531 5286 4318 +3 3765 5286 4531 +3 3971 4439 4435 +3 4673 5134 4114 +3 4426 4701 4013 +3 4058 4653 4444 +3 3966 4891 4494 +3 4140 4902 4454 +3 4311 4906 322 +3 4547 4955 3974 +3 236 4496 237 +3 4298 4592 3900 +3 4655 4783 4115 +3 4464 5247 3891 +3 4255 5247 4464 +3 4250 5149 4954 +3 3979 4591 4321 +3 4321 4591 3833 +3 4436 5227 4224 +3 4327 4806 3890 +3 4510 4908 3802 +3 4475 5316 5165 +3 4295 4650 129 +3 3884 4810 4284 +3 3861 5351 4339 +3 4269 4729 3981 +3 3766 4785 4320 +3 4118 4938 4795 +3 3823 5021 4616 +3 3952 4907 4420 +3 4093 5083 4292 +3 3777 5026 4402 +3 3890 4904 4281 +3 3763 4951 4343 +3 3795 4979 4484 +3 4243 5050 4995 +3 4870 4960 4183 +3 4470 4471 4031 +3 3953 4471 4470 +3 3832 4521 4372 +3 4372 4521 3974 +3 3820 5209 4367 +3 4860 5088 4232 +3 4263 5130 4771 +3 3837 4673 4364 +3 4364 4673 4026 +3 4426 5043 4701 +3 4754 5260 4024 +3 3925 5091 4390 +3 4616 5021 4239 +3 3861 4729 4269 +3 3948 5122 4302 +3 4140 5339 4902 +3 3956 4994 4335 +3 3769 4856 4698 +3 4018 5020 5019 +3 4117 4689 4422 +3 4313 4575 3953 +3 4179 5309 4395 +3 4396 5308 4180 +3 4392 5076 3920 +3 4270 4748 4042 +3 4281 4990 3890 +3 4799 5329 4162 +3 4082 4906 4311 +3 4361 5329 4029 +3 3957 4784 4397 +3 4049 4600 4359 +3 4283 5108 3892 +3 4479 5330 3829 +3 4084 4917 4440 +3 4440 4917 4212 +3 4503 4750 3841 +3 4098 4750 4503 +3 222 4700 223 +3 4277 4722 4027 +3 4264 4864 4413 +3 4247 4981 4974 +3 4025 5113 4319 +3 4274 4827 3887 +3 5123 5184 3886 +3 4003 4616 4579 +3 4049 4547 4521 +3 4521 4547 3974 +3 3993 4820 4553 +3 4282 5214 5119 +3 3890 4948 4327 +3 4269 4807 4020 +3 4121 5029 4336 +3 4278 5164 3812 +3 121 4548 122 +3 4042 4818 4270 +3 4347 5068 4797 +3 4434 5321 3819 +3 3895 5175 4336 +3 4015 5221 4275 +3 4278 5078 4732 +3 4393 4594 3773 +3 4288 4656 3895 +3 4867 4975 4113 +3 3887 5225 4279 +3 4120 5174 4721 +3 4273 4966 3821 +3 4338 4666 220 +3 4275 4762 3878 +3 3915 5054 4293 +3 4731 4781 4023 +3 3877 4822 4273 +3 4628 4673 4114 +3 4026 4673 4628 +3 4337 5340 4478 +3 3996 5139 4282 +3 4027 4833 4277 +3 4660 5222 3995 +3 3971 4459 4439 +3 4318 4960 3961 +3 3812 5078 4278 +3 3943 5152 4738 +3 3876 4769 4278 +3 4321 4804 3892 +3 3974 4514 4372 +3 3931 4523 4363 +3 4017 4812 4279 +3 4279 4812 3887 +3 4401 4505 3779 +3 3977 4505 4401 +3 4331 4667 3809 +3 4471 4546 4031 +3 3831 4546 4471 +3 5235 5271 4258 +3 4365 4900 127 +3 4172 5173 4466 +3 3963 5317 4431 +3 4484 4979 4135 +3 3989 5299 4824 +3 3927 5104 4791 +3 223 4901 224 +3 3892 4998 4283 +3 4280 4866 310 +3 3843 4670 4300 +3 3825 4780 4352 +3 4352 4780 4045 +3 4353 4540 3775 +3 5062 5081 4271 +3 4228 5070 4555 +3 3858 4851 4624 +3 4987 5060 4452 +3 3819 5321 4514 +3 4471 5088 3831 +3 3980 5218 4309 +3 3965 5214 4344 +3 4647 4792 134 +3 3902 4665 4366 +3 4690 4765 4078 +3 3986 4720 4285 +3 4734 4752 4022 +3 3811 4757 4284 +3 4302 4671 3934 +3 4385 4513 4024 +3 323 5135 4311 +3 3986 5073 4983 +3 3844 4828 4371 +3 4284 4743 3884 +3 4683 5085 3826 +3 4358 5074 3803 +3 3895 4977 4288 +3 4028 4708 4297 +3 4573 4988 4194 +3 3790 4988 4573 +3 4059 4681 4419 +3 3783 4544 4360 +3 4475 5165 3877 +3 3940 4567 4490 +3 3989 4824 4577 +3 3778 4693 4326 +3 4109 4606 4409 +3 4612 4938 4118 +3 4974 4981 4067 +3 137 4494 138 +3 4065 5345 4347 +3 3816 4741 4355 +3 4642 5208 4167 +3 3782 4840 4465 +3 4573 5206 4652 +3 4310 4904 3890 +3 4296 5008 3799 +3 4613 5159 4570 +3 4370 4561 3936 +3 3961 4604 4448 +3 4738 5152 4270 +3 4587 5294 4967 +3 3914 5232 4386 +3 4386 5232 4164 +3 3880 5024 4720 +3 3892 4804 4343 +3 3962 4787 4391 +3 4720 5024 4285 +3 3975 4633 4477 +3 3810 4549 4362 +3 4284 4810 3965 +3 4727 4923 3941 +3 4283 4998 4589 +3 4448 5230 4209 +3 3814 5230 4448 +3 4363 4887 3993 +3 3992 4911 4362 +3 4420 4509 3952 +3 4193 4791 4749 +3 4749 4791 3866 +3 4024 4760 4385 +3 4291 5003 250 +3 3826 5085 4808 +3 216 4993 217 +3 4988 5337 3949 +3 4484 5148 3795 +3 4017 4952 4713 +3 4299 4988 3790 +3 4588 4608 3997 +3 4365 5353 3932 +3 4497 5168 3901 +3 4473 4567 3940 +3 4029 4567 4473 +3 308 4450 307 +3 3945 4776 4468 +3 4995 5050 4097 +3 4496 4890 4099 +3 4291 5090 4027 +3 4336 5029 136 +3 3892 5108 4321 +3 4361 4893 4162 +3 4471 5272 5088 +3 4418 5056 4047 +3 4019 4559 4416 +3 4416 4559 3918 +3 3792 4991 4341 +3 4341 4991 4080 +3 4300 4958 3843 +3 3793 5066 4307 +3 3920 5150 4767 +3 4096 5094 5006 +3 4375 4629 4001 +3 295 4447 294 +3 4296 4812 4017 +3 4235 5061 4737 +3 3964 4638 4329 +3 4068 4900 4365 +3 4332 4699 3999 +3 3832 4805 4536 +3 3923 5063 4308 +3 4418 4970 4301 +3 4359 4832 3782 +3 3881 5275 4863 +3 4324 5191 3802 +3 4390 5091 4607 +3 3824 5182 4298 +3 247 4545 248 +3 4877 5042 4149 +3 4312 4933 3800 +3 4053 4933 4312 +3 4187 5082 4405 +3 4099 5081 5062 +3 124 4992 125 +3 137 5029 4494 +3 4700 4901 223 +3 4402 5026 4657 +3 239 5251 4428 +3 3808 4949 4303 +3 4873 5018 3849 +3 3847 5007 4766 +3 4527 4528 3959 +3 4073 4528 4527 +3 3837 4585 4366 +3 3905 5028 4454 +3 4454 5028 4140 +3 3958 5330 4367 +3 3972 4662 4328 +3 3997 5326 4332 +3 4460 4610 3979 +3 4423 4971 3873 +3 4106 4971 4423 +3 3826 4808 4304 +3 4849 5107 3950 +3 4304 5109 4005 +3 3816 5242 4811 +3 4925 5076 4392 +3 4315 5248 3894 +3 4355 4821 3816 +3 4342 5218 3980 +3 3830 5106 4445 +3 3767 4950 4561 +3 4895 5263 4112 +3 4344 5287 3965 +3 4785 4850 4141 +3 3974 4913 4514 +3 3950 5107 4472 +3 4602 5111 3939 +3 4263 5111 4602 +3 4939 5034 225 +3 4080 4632 4341 +3 4282 5119 4522 +3 3833 5001 4321 +3 4550 5073 3986 +3 4012 4843 4696 +3 4940 5323 4225 +3 4156 5114 4501 +3 3911 4688 4323 +3 4529 5297 4175 +3 4616 5123 4579 +3 4345 4943 3999 +3 3849 5018 4504 +3 4584 4725 4089 +3 4369 4658 3897 +3 4075 4658 4369 +3 309 4866 4775 +3 4014 4773 4315 +3 4878 4893 3863 +3 4171 5148 4484 +3 3817 5061 4441 +3 4504 4546 4012 +3 4031 4546 4504 +3 4861 5303 4147 +3 5019 5020 4218 +3 3949 5337 4670 +3 4030 5192 4312 +3 232 4466 233 +3 4687 5002 3913 +3 4249 5002 4687 +3 3975 4629 4516 +3 3919 5190 4333 +3 4587 4967 4105 +3 4317 4728 4011 +3 4692 5235 4258 +3 226 4469 227 +3 4489 5256 4429 +3 4012 4681 4615 +3 4308 4800 3817 +3 4307 5245 4144 +3 4193 4749 4349 +3 3997 4608 4400 +3 4400 4608 3917 +3 4899 5010 4074 +3 3835 4746 4314 +3 4063 5169 4736 +3 4642 5004 4227 +3 3871 5004 4642 +3 4348 5001 3833 +3 4415 4827 4274 +3 3843 4958 4671 +3 4321 5108 3979 +3 4505 4530 4047 +3 4053 4845 4307 +3 4051 4605 4376 +3 4419 4681 3831 +3 4737 5061 3817 +3 4176 5313 4529 +3 321 4502 320 +3 4957 5146 4059 +3 4437 5341 4163 +3 3917 4608 4378 +3 4626 5259 4323 +3 3951 5259 4626 +3 4833 5118 4277 +3 4958 4985 4094 +3 4353 4898 4060 +3 3907 4898 4353 +3 4865 5087 4058 +3 306 4619 305 +3 4345 5023 230 +3 4330 4751 3869 +3 3954 4953 4433 +3 3828 4987 4452 +3 228 4498 229 +3 4549 4688 4046 +3 4345 5207 4122 +3 3973 4904 4310 +3 4478 5340 3955 +3 297 5051 296 +3 4421 5081 4099 +3 4332 4711 3997 +3 4448 4604 3814 +3 4639 5246 3860 +3 4329 5246 4639 +3 4689 5032 4422 +3 4330 4911 3992 +3 126 4631 4365 +3 4316 5033 4014 +3 4007 4594 4393 +3 3812 5296 4337 +3 4165 5220 4736 +3 4496 4609 237 +3 4518 4968 3781 +3 5293 5299 3842 +3 243 5157 4463 +3 3767 4581 4468 +3 4614 4940 4225 +3 3852 4730 4334 +3 4120 4721 4677 +3 4677 4721 4044 +3 3842 5299 4533 +3 4373 4852 3776 +3 3936 4561 4445 +3 4401 4783 3977 +3 4577 5010 4155 +3 4555 5070 4148 +3 4705 4895 4138 +3 4390 4607 3818 +3 141 4491 142 +3 4428 5251 4161 +3 4008 5137 4325 +3 117 4713 118 +3 4185 5211 4575 +3 4846 5125 4166 +3 3992 4751 4330 +3 4534 5253 4136 +3 3814 4604 4472 +3 3885 5118 4833 +3 4323 5289 3810 +3 3991 5182 4552 +3 4518 4519 3984 +3 4035 4519 4518 +3 4162 5329 4361 +3 4580 4760 4137 +3 4041 4819 4651 +3 3901 5168 4960 +3 4528 4714 3803 +3 4073 4714 4528 +3 3999 4699 4345 +3 4322 4793 4020 +3 4054 5112 4333 +3 4093 4908 4510 +3 4517 5178 3987 +3 4482 5197 314 +3 4637 5007 3847 +3 4072 5348 4370 +3 3849 4937 4606 +3 4606 4937 4168 +3 4539 5295 3838 +3 3917 4914 4400 +3 4592 5182 3991 +3 4171 4777 4579 +3 4670 5337 4300 +3 230 4943 4345 +3 4366 4665 4071 +3 4517 5324 3904 +3 4272 5324 4517 +3 4384 4627 3829 +3 4722 5003 4027 +3 131 4499 132 +3 4435 5161 3827 +3 4501 5114 3876 +3 4494 4946 3966 +3 4121 4946 4494 +3 5152 5249 4270 +3 3987 4779 4487 +3 5165 5316 4150 +3 4067 4806 4327 +3 4090 4792 4647 +3 3802 5022 4324 +3 4369 4976 4963 +3 4445 4561 4038 +3 121 5158 4548 +3 4116 5024 4819 +3 3848 5226 4508 +3 4732 5078 4021 +3 135 4792 4336 +3 3947 4586 4432 +3 4105 4698 4417 +3 3838 5295 4902 +3 4648 4886 4013 +3 4653 5048 4444 +3 4857 4881 4280 +3 4044 4881 4857 +3 4341 4756 3792 +3 3992 4935 4554 +3 4553 4934 3993 +3 4085 5194 4322 +3 289 4728 288 +3 4101 4922 4776 +3 4776 4922 4253 +3 4663 4664 4111 +3 3990 4664 4663 +3 4773 5136 4315 +3 4883 5320 4076 +3 237 4609 238 +3 4124 5047 4691 +3 3776 4852 4404 +3 3978 4609 4496 +3 4494 5029 4121 +3 3983 5117 4403 +3 4149 5042 4331 +3 3785 4615 4583 +3 4583 4615 4059 +3 3909 5093 4328 +3 3987 5178 4869 +3 3783 5089 4535 +3 4522 5119 4153 +3 4222 5127 4762 +3 4327 5290 4067 +3 4400 5326 3997 +3 4112 5263 4794 +3 3977 4530 4505 +3 4328 4874 3836 +3 4325 4927 4050 +3 3808 5032 4816 +3 4400 5355 3854 +3 3819 5136 4773 +3 4326 4945 4081 +3 242 5157 243 +3 3999 5279 4332 +3 4033 4704 4371 +3 4760 5143 4385 +3 4880 5129 4022 +3 331 4660 4395 +3 4396 4661 349 +3 4367 5330 4479 +3 4259 5146 4957 +3 4103 4774 4425 +3 4337 4836 3912 +3 3803 4714 4358 +3 4331 4854 3910 +3 4116 4819 4645 +3 4013 4701 4648 +3 4648 4701 4100 +3 4220 5034 4939 +3 4160 5022 4638 +3 4001 4629 4477 +3 4064 4959 4330 +3 4334 5217 4063 +3 3944 4740 4354 +3 5030 5038 4143 +3 4140 5028 4588 +3 4714 4879 3948 +3 3802 5191 4510 +3 3788 5068 4347 +3 3851 4774 4587 +3 4587 4774 4103 +3 314 5197 313 +3 4663 5203 3990 +3 4009 5255 5142 +3 4395 4660 3995 +3 3994 4661 4396 +3 3838 4630 4539 +3 4539 4630 4102 +3 3868 4820 4380 +3 4631 5353 4365 +3 4493 5090 3888 +3 4402 4657 3923 +3 4425 5031 3807 +3 4142 4596 4560 +3 4018 5019 4487 +3 4886 5305 4013 +3 4423 5086 3985 +3 4346 4972 319 +3 3906 4754 4355 +3 4386 4680 3914 +3 4332 5326 4699 +3 3781 4968 4755 +3 4819 5105 4651 +3 4056 4976 4340 +3 4349 5150 3920 +3 4299 5337 4988 +3 4343 4804 4066 +3 3898 4926 4374 +3 251 4722 252 +3 4243 4995 4501 +3 4356 5137 4008 +3 4348 5013 4065 +3 3833 5013 4348 +3 4603 5089 3783 +3 4725 5043 4089 +3 4834 5025 3850 +3 4340 4939 224 +3 3924 4668 4404 +3 4077 5189 4779 +3 4371 4828 4033 +3 3845 4675 4446 +3 4446 4675 4030 +3 4372 5321 3962 +3 4032 4765 4690 +3 4377 5187 4040 +3 3815 4697 4382 +3 4582 5196 4290 +3 4369 4963 3834 +3 4001 4603 4458 +3 4225 5107 4849 +3 4793 5277 4190 +3 3859 5344 4379 +3 4740 4949 3808 +3 4383 5139 3996 +3 3894 4788 4398 +3 4398 4788 4151 +3 4406 4674 4010 +3 4775 4866 4139 +3 4319 5233 4618 +3 4183 5168 4817 +3 3867 4895 4705 +3 4266 5320 4883 +3 4674 5226 3848 +3 4699 5326 3854 +3 4340 4901 4056 +3 4615 4843 4012 +3 4565 5283 4184 +3 3763 5319 4361 +3 4046 4761 4368 +3 4368 4761 218 +3 3993 4887 4380 +3 4726 5285 3794 +3 4313 4828 4575 +3 4276 5331 4743 +3 4003 4777 4378 +3 4691 4766 4124 +3 4062 4766 4691 +3 3839 4781 4357 +3 4421 5275 5081 +3 4078 4765 4535 +3 4549 5289 4688 +3 4776 5110 4468 +3 4701 5043 3768 +3 3823 4616 4483 +3 304 4838 4351 +3 4457 5012 3998 +3 4040 4885 4377 +3 4354 4816 3945 +3 4351 4839 303 +3 5046 5135 324 +3 3995 4703 4395 +3 4396 4702 3994 +3 4511 5271 3908 +3 4213 5271 4511 +3 4458 4603 3783 +3 4963 4976 4056 +3 3839 4633 4509 +3 4045 5276 4352 +3 4771 5054 4082 +3 4293 5054 4771 +3 4146 4858 4647 +3 4647 4858 4090 +3 4497 4899 4074 +3 3829 4627 4449 +3 3776 5137 4356 +3 4450 5162 307 +3 3781 4755 4495 +3 4495 4755 4057 +3 4575 5211 3953 +3 4083 5060 4987 +3 4007 4747 4568 +3 4845 5192 3870 +3 4472 4604 4043 +3 3966 4946 4560 +3 220 4666 221 +3 4381 5301 4170 +3 4443 5133 346 +3 4122 5023 4345 +3 4877 4892 341 +3 3921 4715 4393 +3 4393 4715 4007 +3 4075 5241 4658 +3 4070 5287 4982 +3 4541 4813 4186 +3 4469 5160 4969 +3 4736 5169 4165 +3 4982 5287 4344 +3 4384 5330 3958 +3 4695 5113 4025 +3 4463 4809 243 +3 4666 5196 4132 +3 3775 4862 4353 +3 3915 5005 4346 +3 4364 5036 4035 +3 3764 4727 4391 +3 3778 5167 4381 +3 4623 5255 4009 +3 4347 5345 3788 +3 4002 5277 4583 +3 4973 5241 4075 +3 4386 4737 3817 +3 3818 4739 4390 +3 3831 4681 4546 +3 4500 4802 3929 +3 4071 4802 4500 +3 291 5187 4377 +3 4367 5209 3958 +3 4366 5205 3837 +3 4291 5266 5090 +3 352 4553 351 +3 329 4554 328 +3 4068 5219 4389 +3 4452 4692 3828 +3 4465 4639 4091 +3 4484 4914 3917 +3 4416 4725 4019 +3 3768 4725 4416 +3 4401 4724 3928 +3 4569 4778 3908 +3 4095 4778 4569 +3 4534 4602 3939 +3 4163 4602 4534 +3 4638 5022 3802 +3 3921 5341 4437 +3 4947 4965 4192 +3 3967 4832 4359 +3 3865 5267 4519 +3 4863 5201 4210 +3 4378 4777 3917 +3 4103 4865 4686 +3 4353 5058 3907 +3 4408 4712 3830 +3 302 4829 301 +3 4204 4987 4894 +3 3941 4805 4388 +3 3879 5210 4640 +3 3934 5074 4358 +3 4359 5124 3967 +3 4028 5163 4384 +3 3822 4824 4576 +3 4441 5061 3982 +3 228 4969 4498 +3 4467 4678 3822 +3 4214 5094 4744 +3 3812 5164 4415 +3 4138 5162 4450 +3 4133 5151 4438 +3 4438 5151 3805 +3 4076 4756 4454 +3 298 4695 297 +3 5049 5214 3777 +3 343 4565 342 +3 4624 4789 3858 +3 4107 4789 4624 +3 4483 4616 4003 +3 3914 5116 4443 +3 4443 5116 4129 +3 4191 4854 4392 +3 3998 5012 4507 +3 4103 5254 4865 +3 4139 5183 4775 +3 4791 5104 4168 +3 4002 5352 5277 +3 4414 5136 3819 +3 4113 5136 4414 +3 254 4986 4 +3 4 4986 115 +3 4545 4709 4004 +3 4366 5147 3902 +3 4720 5220 3880 +3 4413 4876 3813 +3 4357 5009 4223 +3 4477 4629 3975 +3 4292 5079 4646 +3 4538 4649 3834 +3 3784 4818 4708 +3 4201 4915 4755 +3 4755 4915 4057 +3 4762 5127 3878 +3 4064 5128 4373 +3 3846 4784 4598 +3 4477 4633 3839 +3 4380 4820 3993 +3 4455 4782 3969 +3 4406 5167 3778 +3 3811 4887 4363 +3 3999 4943 4498 +3 4015 4652 4461 +3 4504 4696 3849 +3 3827 5161 4704 +3 4371 5161 3980 +3 4530 4750 4047 +3 3987 4869 4779 +3 4679 4735 3855 +3 3878 5127 4542 +3 4545 5155 248 +3 3830 4803 4408 +3 4362 4911 3810 +3 4391 4787 3764 +3 3998 4733 4457 +3 4344 5214 5049 +3 4402 5049 3777 +3 3865 5036 4745 +3 4464 5126 4255 +3 3910 5239 4411 +3 4411 5239 4131 +3 345 4859 344 +3 4368 5075 4046 +3 4817 4835 4183 +3 3798 4835 4817 +3 3831 4742 4419 +3 4397 4784 3846 +3 3854 5326 4400 +3 4405 5082 3835 +3 3930 5075 4368 +3 3908 5271 5235 +3 4397 4880 4022 +3 4498 4969 4102 +3 4154 5224 4836 +3 4723 4936 4086 +3 3928 4783 4401 +3 4520 4965 4015 +3 4405 5189 3913 +3 3976 5208 4642 +3 3962 5292 4787 +3 4071 5205 4366 +3 4219 4973 4918 +3 4469 4969 227 +3 4568 5166 4007 +3 3897 4976 4369 +3 4477 5171 4001 +3 4632 4941 3844 +3 3885 5281 5195 +3 4374 5056 3898 +3 4379 5142 4174 +3 4370 5348 3767 +3 4383 4851 4048 +3 139 4944 140 +3 129 4650 130 +3 4466 5173 233 +3 122 4707 123 +3 4006 4678 4467 +3 4548 4707 122 +3 3958 5256 4489 +3 5083 5132 4292 +3 4437 4715 3921 +3 4560 4596 3966 +3 4662 5132 3909 +3 4047 5056 4374 +3 4465 4955 3782 +3 4091 4955 4465 +3 4379 5116 3914 +3 4123 4692 4452 +3 4346 5005 4972 +3 4972 5005 4061 +3 4246 5220 4720 +3 319 4972 318 +3 346 4912 4443 +3 4706 4925 3809 +3 125 4631 126 +3 4457 4733 3786 +3 4007 5166 4594 +3 134 4792 135 +3 3853 4858 4551 +3 4551 4858 4146 +3 4083 4855 4512 +3 4512 4855 3942 +3 4428 4745 4026 +3 3955 4684 4478 +3 4579 5097 4171 +3 3886 5097 4579 +3 243 4809 244 +3 4377 5035 291 +3 4125 5249 5152 +3 324 5135 323 +3 4774 4915 4201 +3 3851 4915 4774 +3 4088 5011 4897 +3 4380 4980 4070 +3 4511 4778 4014 +3 4287 4921 4399 +3 4743 5331 3884 +3 4620 5062 4271 +3 4074 4678 4637 +3 4637 4678 4006 +3 4114 5157 4628 +3 4399 4921 4194 +3 4188 5129 4880 +3 4180 5308 4553 +3 4554 5309 4179 +3 346 5133 345 +3 4478 4684 4021 +3 4000 4707 4548 +3 4389 5072 3916 +3 340 4892 4411 +3 4390 5222 4196 +3 4822 5165 4261 +3 4542 5127 4152 +3 4430 5261 3801 +3 305 4838 304 +3 4015 4965 4573 +3 303 4839 302 +3 4818 5250 4708 +3 4723 5357 4936 +3 4267 5185 5138 +3 4048 5026 4383 +3 3864 4844 4634 +3 4634 4844 4117 +3 4020 4807 4488 +3 4404 4852 3983 +3 3921 5020 4430 +3 3903 5131 5044 +3 3821 5317 4654 +3 3893 4797 4424 +3 4399 5230 3814 +3 4385 5143 4128 +3 4264 5278 4864 +3 4640 5210 4203 +3 4753 5050 4243 +3 3789 5050 4753 +3 3846 4880 4397 +3 4109 4907 4884 +3 4110 4827 4415 +3 4567 5099 4490 +3 4499 5039 132 +3 4453 5257 5190 +3 293 4676 292 +3 4662 4971 4106 +3 4408 5063 3923 +3 4079 5063 4408 +3 3961 4870 4604 +3 4894 4987 3828 +3 5090 5266 3888 +3 4643 4886 3845 +3 5044 5131 4351 +3 4485 5069 3836 +3 3855 5264 4922 +3 3809 4925 4392 +3 3982 5049 4402 +3 3819 4773 4434 +3 4646 4975 3860 +3 4151 4975 4646 +3 4584 5059 4019 +3 4164 5176 4386 +3 4481 4764 3826 +3 3821 4966 4431 +3 4453 5190 3919 +3 4042 4748 4492 +3 4492 4748 3840 +3 4489 4708 4028 +3 4461 5221 4015 +3 4501 5353 4156 +3 4506 5008 4296 +3 4026 5084 4428 +3 141 5057 4491 +3 4537 4656 3967 +3 4409 5104 3927 +3 4150 5316 4447 +3 4665 4947 4071 +3 3825 5227 4436 +3 4118 4875 4612 +3 4612 4875 4039 +3 3857 4929 4596 +3 3862 4930 4480 +3 5120 5239 4382 +3 4474 4928 3956 +3 230 5023 231 +3 4062 4871 4766 +3 4389 5219 3836 +3 3771 5186 4614 +3 4413 4864 4119 +3 349 4661 348 +3 332 4660 331 +3 4436 4780 3825 +3 4109 4873 4606 +3 4606 4873 3849 +3 4644 5318 3897 +3 145 5046 3 +3 3 5046 324 +3 4091 4867 4414 +3 133 4647 134 +3 3841 4750 4530 +3 309 4775 308 +3 3790 4965 4947 +3 4735 5264 3855 +3 3784 4708 4489 +3 4535 4765 3783 +3 4918 4973 4075 +3 4996 5071 4128 +3 4668 4742 4050 +3 4247 4974 4610 +3 4004 4876 4413 +3 4967 5294 3899 +3 4082 5054 4502 +3 4012 4696 4504 +3 4969 5160 4102 +3 4521 5014 4049 +3 4460 5210 4610 +3 5091 5352 4002 +3 4824 5299 4200 +3 3926 5201 4863 +3 4022 5071 4397 +3 4419 4957 4059 +3 3924 4957 4419 +3 4173 5184 4407 +3 3851 5273 4417 +3 4099 4890 4421 +3 4421 4890 235 +3 302 4839 4829 +3 4914 5355 4400 +3 3852 4837 4730 +3 4131 5239 5120 +3 4010 5167 4406 +3 3824 5053 4552 +3 4403 5117 3818 +3 231 4903 232 +3 4119 5252 4413 +3 4413 5252 4004 +3 4411 5234 3910 +3 4009 5142 4680 +3 3783 4765 4544 +3 5193 5202 4265 +3 4048 4712 4657 +3 4333 5112 4462 +3 4422 5307 4117 +3 4376 5122 4978 +3 4447 5316 3933 +3 3988 5226 4406 +3 294 5238 293 +3 4516 4704 4033 +3 4506 5281 3885 +3 4502 4906 4082 +3 321 4906 4502 +3 4447 5304 4150 +3 4978 5122 3948 +3 4600 5124 4359 +3 3864 5012 4844 +3 4876 5221 3813 +3 4211 4799 4694 +3 3774 5143 4760 +3 4159 5306 4424 +3 4414 4913 4091 +3 4149 4892 4877 +3 4423 5228 4106 +3 4478 5078 3812 +3 342 4877 341 +3 4130 5300 4424 +3 4562 4733 3998 +3 4415 5231 4110 +3 308 4775 4450 +3 3898 5056 4418 +3 4507 4706 3998 +3 4424 5300 3893 +3 225 5034 226 +3 247 4709 4545 +3 4514 5321 4372 +3 4172 5275 4421 +3 4031 4850 4470 +3 3909 5132 5083 +3 4654 5317 4248 +3 246 4709 247 +3 3987 4719 4517 +3 4420 4907 3804 +3 4433 4953 4023 +3 4677 5197 4120 +3 4546 4681 4012 +3 3827 4704 4516 +3 4055 4894 4571 +3 4869 5040 4077 +3 4286 5040 4869 +3 4558 4684 3955 +3 353 4934 352 +3 328 4935 327 +3 4417 5208 3976 +3 142 5067 143 +3 4412 5041 3928 +3 3985 4772 4595 +3 4462 5112 3764 +3 4147 4684 4558 +3 3771 5274 5186 +3 3800 4933 4868 +3 4868 4933 4241 +3 4093 5246 4908 +3 4417 5273 4105 +3 3976 4642 4641 +3 4641 4642 4227 +3 5073 5298 4127 +3 4265 5202 4493 +3 4495 4841 3934 +3 4057 4841 4495 +3 4032 4764 4481 +3 4098 4970 4418 +3 3864 4917 4507 +3 4507 4917 4084 +3 4683 5188 4034 +3 5009 5089 4223 +3 4000 5164 4769 +3 4434 5096 4095 +3 3969 5307 4422 +3 4866 5315 4139 +3 4270 5249 4748 +3 4769 5164 4278 +3 295 5304 4447 +3 4053 5000 4933 +3 4430 5341 3921 +3 3801 5342 4430 +3 4429 5338 4231 +3 4509 4781 3839 +3 4442 4915 3851 +3 4057 4915 4442 +3 4749 5150 4349 +3 4754 4821 4355 +3 4774 5327 4425 +3 4699 5207 4345 +3 4158 5066 4617 +3 4617 5066 3793 +3 4705 5000 3867 +3 4241 5000 4705 +3 4472 4813 3950 +3 4043 4813 4472 +3 314 4889 4482 +3 4734 5185 4267 +3 3793 5185 4734 +3 318 4972 4825 +3 4480 4930 4069 +3 3836 5069 4557 +3 4563 5201 3926 +3 4553 5308 351 +3 329 5309 4554 +3 4117 4848 4689 +3 4802 4947 4192 +3 4071 4947 4802 +3 229 4943 230 +3 4192 4965 4520 +3 4689 4848 3855 +3 4815 5138 4144 +3 3981 4831 4599 +3 4115 5041 5027 +3 4908 5246 4329 +3 347 4912 346 +3 4114 5134 4463 +3 4463 5134 3929 +3 4422 5032 3808 +3 4425 5254 4103 +3 4606 5104 4409 +3 4431 5317 3821 +3 4101 5032 4689 +3 4067 4981 4806 +3 4234 4936 4598 +3 4108 5168 4497 +3 4079 4672 4623 +3 3988 5163 4508 +3 3873 5086 4423 +3 4444 5291 4058 +3 343 5283 4565 +3 4038 4735 4524 +3 4487 4779 3835 +3 4465 4840 3964 +3 5265 5284 4462 +3 3929 5335 4463 +3 3793 5129 4617 +3 4830 4853 335 +3 4696 4843 4085 +3 3926 5154 4563 +3 4602 5342 3801 +3 3939 5253 4534 +3 3818 5117 4739 +3 4739 5117 4236 +3 240 5084 241 +3 4482 5174 4120 +3 3935 5174 4482 +3 3807 5254 4425 +3 4543 5192 4030 +3 3891 4826 4464 +3 5057 5253 4491 +3 3904 5125 4846 +3 4513 4821 4024 +3 4623 4672 3786 +3 4429 5256 4238 +3 4671 4958 4094 +3 4431 4966 4025 +3 3877 5165 4822 +3 4137 4717 4550 +3 3881 5087 5081 +3 3860 4975 4867 +3 4437 5350 4142 +3 3857 5350 4437 +3 4041 4931 4611 +3 4011 4757 4523 +3 4933 5000 4241 +3 4526 4847 4240 +3 3941 4923 4438 +3 4556 5066 4158 +3 4910 5191 4324 +3 4220 5318 4644 +3 4797 5068 4034 +3 4089 5043 4426 +3 4158 5263 4556 +3 4503 4786 4098 +3 3935 4786 4503 +3 345 5133 4859 +3 4824 5170 4576 +3 4524 4803 3830 +3 4438 5333 3941 +3 3889 5323 4940 +3 4217 5166 5144 +3 4763 4834 3850 +3 4133 4834 4763 +3 4072 5298 4427 +3 3801 5261 4532 +3 4428 5084 240 +3 3810 4959 4626 +3 4036 4856 4525 +3 4100 4675 4648 +3 4648 4675 3845 +3 4448 5288 3961 +3 3991 5009 4592 +3 4027 5090 4493 +3 4571 5172 3907 +3 4258 5172 4571 +3 3908 4778 4511 +3 4470 4850 3766 +3 3946 5295 4539 +3 4275 5221 4876 +3 4014 5033 4511 +3 4612 4905 3856 +3 4830 5030 4143 +3 4237 5030 4830 +3 3770 5228 4564 +3 4747 5115 4568 +3 4059 5146 4583 +3 4651 4931 4041 +3 4174 4733 4562 +3 4279 5225 4636 +3 4280 5315 4866 +3 4044 4857 4677 +3 4037 4801 4672 +3 4136 4944 4929 +3 4929 4944 4254 +3 4199 4861 4480 +3 4589 4875 3791 +3 3934 5198 4495 +3 120 5158 121 +3 4446 4924 3845 +3 4864 5278 3888 +3 4019 4725 4584 +3 4679 4801 4037 +3 4339 5352 5091 +3 4646 5079 4151 +3 334 4853 4486 +3 3764 5265 4462 +3 3932 5353 4501 +3 4155 5286 4625 +3 4499 5237 5039 +3 4579 4777 4003 +3 4123 5284 5265 +3 3804 5126 4433 +3 4454 4902 4076 +3 4555 5068 3788 +3 4095 5292 4434 +3 4143 4853 4830 +3 231 5023 4903 +3 138 4891 139 +3 4742 5088 4050 +3 4203 5216 4640 +3 4640 5216 3942 +3 292 5187 291 +3 4475 4872 3933 +3 4639 4867 4091 +3 4035 5036 4519 +3 4544 4765 4032 +3 4099 5062 4496 +3 4496 5062 3978 +3 4480 4861 4147 +3 4040 5187 4676 +3 218 4761 219 +3 4542 4802 4192 +3 3929 4802 4542 +3 4734 5129 3793 +3 4438 5262 4133 +3 4759 4882 4130 +3 4758 5144 3882 +3 4490 5101 3940 +3 4518 5100 4035 +3 3980 5161 4435 +3 4444 5048 3795 +3 299 5233 5113 +3 4267 5138 4635 +3 4233 5059 4578 +3 4713 5281 4017 +3 4268 5281 4713 +3 3940 5101 4492 +3 4705 5354 3937 +3 4005 5109 4525 +3 4037 4803 4524 +3 4600 4758 3882 +3 4716 5340 4294 +3 3955 5340 4716 +3 4005 5021 4586 +3 4643 5203 4886 +3 5026 5139 4383 +3 3777 5139 5026 +3 3919 5060 4453 +3 4453 5060 4083 +3 241 5084 4628 +3 232 4903 4466 +3 4119 5155 4545 +3 3785 5277 4793 +3 4440 5076 4084 +3 5190 5257 4111 +3 4548 5158 4110 +3 336 4830 335 +3 4647 5039 4146 +3 133 5039 4647 +3 315 4889 314 +3 4607 5091 4002 +3 4043 4870 4835 +3 4018 5261 5020 +3 5020 5261 4430 +3 4556 5263 3867 +3 4571 5058 4055 +3 4221 5147 4585 +3 4594 5166 4217 +3 4205 5334 4772 +3 4307 5066 4556 +3 3774 4760 4580 +3 4048 5106 4712 +3 4717 5260 3906 +3 4216 5144 4758 +3 4536 4805 4198 +3 4049 5014 4758 +3 4134 5150 4749 +3 4976 5318 4340 +3 5138 5185 4144 +3 4814 5177 3879 +3 4452 5284 4123 +3 3919 5284 4452 +3 4450 5354 4138 +3 3937 5354 4450 +3 4983 5073 4127 +3 5195 5281 4268 +3 4016 4928 4474 +3 4795 4938 4089 +3 3957 4996 4456 +3 4129 5133 4443 +3 4443 5232 3914 +3 4698 5208 4417 +3 4447 5238 294 +3 3860 4867 4639 +3 4473 4951 3763 +3 4768 4790 4107 +3 3787 4790 4768 +3 4049 4758 4600 +3 4135 4914 4484 +3 4862 5177 4055 +3 4325 5137 4927 +3 4927 5137 3776 +3 310 4866 309 +3 4331 5042 4667 +3 3950 4813 4541 +3 4384 5163 4627 +3 4104 5093 4510 +3 4510 5093 3909 +3 4135 5201 4563 +3 4627 5163 3988 +3 4597 5227 3825 +3 4096 4924 4724 +3 4661 5077 348 +3 4578 5059 3856 +3 341 4892 340 +3 4321 5001 4804 +3 4494 4891 138 +3 3991 5089 5009 +3 4960 5103 3901 +3 4318 5103 4960 +3 4452 5060 3919 +3 4767 5150 4134 +3 3952 5347 4785 +3 4785 5347 4320 +3 4636 5158 120 +3 4142 5350 4596 +3 332 5215 4660 +3 4525 5109 4036 +3 4835 4870 4183 +3 5081 5087 4271 +3 4846 5178 3904 +3 4286 5178 4846 +3 4589 4998 4195 +3 4595 4772 4108 +3 4019 4811 4559 +3 5015 5063 4079 +3 4910 5180 3916 +3 4324 5180 4910 +3 4175 5135 5046 +3 4133 5336 5151 +3 3796 5257 4453 +3 4138 4895 4619 +3 4525 4856 3769 +3 4308 5063 5015 +3 226 5034 4469 +3 4672 4801 3786 +3 4855 4987 4204 +3 4083 4987 4855 +3 4584 4938 3856 +3 4089 4938 4584 +3 4060 5349 4467 +3 4563 5154 4122 +3 4073 4879 4714 +3 5103 5286 4155 +3 4178 5124 4600 +3 3855 4848 4679 +3 4679 4848 4092 +3 4669 5266 4291 +3 4863 5275 4172 +3 4819 5024 3880 +3 4316 5047 5033 +3 5033 5047 3794 +3 4466 5154 3926 +3 248 5155 249 +3 3989 5312 4533 +3 4533 5312 4157 +3 4913 4955 4091 +3 4462 5284 3919 +3 4080 4941 4632 +3 4490 5099 3848 +3 4195 4998 4956 +3 4203 5210 4460 +3 3813 5221 4461 +3 4016 4940 4614 +3 4251 5008 4506 +3 4498 4943 229 +3 4510 5191 4104 +3 4463 5157 4114 +3 4468 5110 3767 +3 3897 5318 4976 +3 4577 4824 3822 +3 5035 5052 290 +3 4605 4919 3843 +3 4081 4945 4826 +3 4339 5091 5038 +3 5038 5091 3925 +3 4575 4828 3844 +3 4467 5229 4006 +3 224 4939 225 +3 3953 5272 4471 +3 3933 5316 4475 +3 3836 5219 4485 +3 4487 5019 3987 +3 3946 5160 4469 +3 3884 5311 4810 +3 299 5113 298 +3 335 4853 334 +3 3985 4871 4564 +3 4564 4871 4062 +3 4724 5094 4096 +3 3964 4840 4590 +3 3961 5288 4531 +3 4361 5319 4893 +3 4893 5319 4130 +3 4167 4856 4718 +3 4651 5169 3787 +3 4165 5169 4651 +3 4492 5011 3940 +3 5113 5233 4319 +3 4021 5078 4478 +3 4129 4961 4859 +3 4859 4961 4184 +3 4087 4989 4932 +3 4146 5237 4551 +3 4551 5237 3938 +3 3799 5202 5193 +3 4284 4757 4743 +3 4570 5159 4199 +3 4201 5327 4774 +3 4638 5356 4160 +3 4510 5083 4093 +3 3909 5083 4510 +3 4791 4916 3866 +3 4168 4916 4791 +3 4628 5084 4026 +3 4029 5329 4799 +3 3913 5189 4687 +3 3839 5171 4477 +3 4160 5268 4551 +3 6 5213 216 +3 7 5212 355 +3 325 5213 6 +3 286 5212 7 +3 4670 4919 4209 +3 4223 5089 4603 +3 4006 5229 4726 +3 4197 5302 4888 +3 4501 4995 3932 +3 4486 5343 3925 +3 4696 4937 3849 +3 4120 5197 4482 +3 4025 4966 4822 +3 4822 4966 4273 +3 4964 5079 4292 +3 3770 5079 4964 +3 4561 4950 4038 +3 4491 5067 142 +3 4604 4870 4043 +3 4652 5206 3889 +3 4204 4894 4814 +3 4951 5011 4088 +3 3858 5217 4685 +3 4771 5130 4293 +3 4590 4840 4126 +3 4276 5052 5035 +3 3863 5064 4690 +3 4659 4961 3859 +3 4184 4961 4659 +3 4141 5018 4873 +3 4732 4753 4243 +3 4021 4753 4732 +3 4504 5018 4031 +3 235 4890 236 +3 3890 4990 4948 +3 4069 4930 4896 +3 4896 4930 4186 +3 4556 5000 4053 +3 3959 4932 4527 +3 4488 5121 4134 +3 4788 4975 4151 +3 4113 4975 4788 +3 4500 5205 4071 +3 4507 5012 3864 +3 4599 5120 3981 +3 4131 5120 4599 +3 4766 5007 4124 +3 4485 5219 4068 +3 4492 5101 4042 +3 3838 5279 4630 +3 4640 4855 4204 +3 3942 4855 4640 +3 4036 5258 4718 +3 4630 5279 3999 +3 4718 4856 4036 +3 4769 5114 4208 +3 3876 5114 4769 +3 4565 4877 342 +3 4163 5342 4602 +3 3984 4968 4518 +3 127 4900 128 +3 3843 4919 4670 +3 4046 5075 4549 +3 4266 4883 4644 +3 4134 5240 4488 +3 3764 5112 4727 +3 4077 5040 4687 +3 322 4906 321 +3 4680 4800 4009 +3 4219 4918 4710 +3 4610 5210 3879 +3 4609 5251 238 +3 4161 5251 4609 +3 4578 5152 3943 +3 4125 5152 4578 +3 4743 4757 4011 +3 4491 5253 3939 +3 5085 5258 4036 +3 4779 4869 4077 +3 4529 5140 144 +3 4175 5140 4529 +3 250 5003 251 +3 4956 4998 3892 +3 4092 4801 4679 +3 3845 4924 4643 +3 4643 4924 4096 +3 4701 4888 4100 +3 3768 4888 4701 +3 3945 4816 4776 +3 4776 4816 4101 +3 5081 5275 3881 +3 4671 5198 3934 +3 4645 4819 4041 +3 4585 5147 4366 +3 4031 5018 4850 +3 4275 4876 4762 +3 4762 4876 4004 +3 5031 5327 3984 +3 4425 5327 5031 +3 3867 5263 4895 +3 3835 5082 4746 +3 4829 4839 4086 +3 4542 5335 3929 +3 4152 5335 4542 +3 339 5102 338 +3 4493 5202 4251 +3 3832 5014 4521 +3 4039 4875 4589 +3 4509 5347 3952 +3 3785 4843 4615 +3 4302 5122 4605 +3 4595 4871 3985 +3 4694 4799 3824 +3 3855 4922 4689 +3 4689 4922 4101 +3 4081 4949 4740 +3 4883 5295 3946 +3 4167 5208 4698 +3 3929 5134 4500 +3 118 4952 119 +3 3954 4945 4693 +3 4693 4945 4326 +3 4087 4932 4566 +3 4566 4932 3959 +3 4633 5347 4509 +3 4738 4818 3784 +3 4270 4818 4738 +3 352 4934 4553 +3 4554 4935 328 +3 4206 5141 4515 +3 4515 5141 316 +3 3938 5237 4499 +3 3842 5017 4527 +3 4527 5017 4073 +3 4519 5036 3865 +3 3782 4955 4547 +3 3837 5205 4500 +3 4780 4872 4045 +3 4690 5064 4032 +3 4298 5182 4592 +3 4597 4885 4040 +3 4503 5174 3935 +3 249 5155 4669 +3 290 5052 289 +3 4552 5053 4078 +3 4533 5017 3842 +3 227 4969 228 +3 4790 5169 4063 +3 4056 4901 4700 +3 4611 4931 4226 +3 4786 5145 4098 +3 4653 5087 3881 +3 4508 5163 4028 +3 4882 5300 4130 +3 4789 5217 3858 +3 4800 5015 4009 +3 3822 5010 4577 +3 4107 4790 4789 +3 4789 4790 4063 +3 4807 5121 4488 +3 4711 5279 3838 +3 4017 5281 4506 +3 4816 5032 4101 +3 4508 5226 3988 +3 4070 4980 4574 +3 3781 5100 4518 +3 3979 4974 4591 +3 4308 5015 4800 +3 4664 5025 4111 +3 3850 5025 4664 +3 4678 5010 3822 +3 4122 5207 4563 +3 4563 5207 3854 +3 3983 5128 4572 +3 3867 5000 4556 +3 4126 5181 4590 +3 4590 5181 3853 +3 4058 5291 4686 +3 4070 4982 4601 +3 4573 4965 3790 +3 3873 4971 4570 +3 4666 5095 221 +3 4132 5095 4666 +3 4875 5037 3791 +3 4551 5268 3853 +3 4287 5323 4921 +3 291 5035 290 +3 4836 5224 3912 +3 4519 5267 3984 +3 4051 4919 4605 +3 4182 5242 4513 +3 4574 4980 3811 +3 4733 5255 3786 +3 4764 5188 3826 +3 4619 4895 4112 +3 338 5102 4599 +3 4124 5007 4726 +3 4726 5007 4006 +3 5142 5255 4174 +3 3834 4963 4582 +3 136 5029 137 +3 4778 5096 4014 +3 4055 5058 4862 +3 300 5233 299 +3 3904 5178 4517 +3 4333 5190 5025 +3 5025 5190 4111 +3 140 5057 141 +3 4619 5162 4138 +3 306 5162 4619 +3 4039 4905 4612 +3 4128 5143 4996 +3 132 5039 133 +3 4535 5089 3991 +3 3912 5224 4994 +3 4994 5224 4335 +3 3905 5218 5028 +3 5028 5218 4342 +3 4598 4936 3846 +3 4946 5175 4289 +3 4121 5175 4946 +3 4539 5160 3946 +3 4102 5160 4539 +3 4065 4948 4593 +3 4109 4884 4873 +3 4873 4884 4141 +3 4845 5245 4307 +3 4574 5287 4070 +3 4463 5335 4809 +3 4022 5129 4734 +3 4579 5123 3886 +3 4644 4883 3946 +3 4097 5069 4995 +3 4667 5042 3970 +3 4610 4974 3979 +3 4517 5314 4272 +3 3845 4886 4648 +3 4032 5064 4764 +3 4697 5120 4382 +3 4067 5290 4591 +3 4686 4865 4058 +3 3768 5043 4725 +3 4024 4821 4754 +3 3788 5345 4593 +3 4591 4974 4067 +3 4984 5198 4094 +3 4136 5253 5057 +3 4704 5161 4371 +3 4169 5305 4886 +3 3767 5348 4581 +3 5144 5166 3882 +3 221 5095 222 +3 348 5077 347 +3 4023 4953 4731 +3 4638 4908 4329 +3 3802 4908 4638 +3 4758 5014 4216 +3 4078 4878 4690 +3 4690 4878 3863 +3 4106 5132 4662 +3 4569 5235 4123 +3 3908 5235 4569 +3 3820 5073 4550 +3 3856 4938 4612 +3 119 5346 120 +3 4034 5068 4555 +3 4013 5305 4526 +3 4200 5299 5293 +3 4008 4918 4649 +3 296 5304 295 +3 4601 4982 3982 +3 4557 5069 4097 +3 4626 4959 4064 +3 4962 5181 4126 +3 4288 5181 4962 +3 3987 5019 4719 +3 3907 5058 4571 +3 4545 5252 4119 +3 4004 5252 4545 +3 4168 4937 4916 +3 4916 4937 4085 +3 4531 5288 4051 +3 4148 5085 4683 +3 4000 5231 5164 +3 5164 5231 4415 +3 4098 5145 4970 +3 4085 4937 4696 +3 4649 4918 4075 +3 4850 5018 4141 +3 4054 4923 4727 +3 4173 4997 4967 +3 4096 5006 4643 +3 4643 5006 3990 +3 4657 5026 4048 +3 4533 5299 3989 +3 144 5140 145 +3 4763 5336 4133 +3 316 5141 315 +3 4770 4905 4039 +3 4125 4905 4770 +3 4526 5305 4847 +3 3870 5192 4543 +3 3964 5356 4638 +3 307 5162 306 +3 4656 4962 3967 +3 3787 4931 4651 +3 233 5173 234 +3 4950 5110 4253 +3 3767 5110 4950 +3 4211 5099 4567 +3 3856 5059 4584 +3 4548 5231 4000 +3 4110 5231 4548 +3 4582 5244 4132 +3 4921 5323 3889 +3 3889 4940 4652 +3 4105 4997 4698 +3 4698 4997 3769 +3 4773 5096 4434 +3 4288 4962 4656 +3 4050 4927 4668 +3 4885 5331 4377 +3 4576 5170 3973 +3 4623 5015 4079 +3 4552 5182 3824 +3 4097 5050 4613 +3 4613 5050 3789 +3 4726 5047 4124 +3 3794 5047 4726 +3 4174 5255 4733 +3 333 5215 332 +3 4568 5115 4178 +3 4115 5092 4655 +3 4655 5092 3874 +3 4543 5302 3870 +3 4719 5019 4218 +3 4219 4991 4973 +3 4973 4991 3792 +3 3861 5030 4729 +3 4729 5030 4237 +3 238 5251 239 +3 4572 5128 4064 +3 4292 5132 4964 +3 4159 5188 4764 +3 4596 5350 3857 +3 4036 5109 4808 +3 355 5269 354 +3 326 5270 325 +3 344 5283 343 +3 4009 5015 4623 +3 4373 5128 4852 +3 5035 5331 4276 +3 4377 5331 5035 +3 330 5309 329 +3 351 5308 350 +3 3882 5166 4568 +3 3810 5289 4549 +3 4950 5264 4038 +3 4104 5072 4874 +3 5151 5336 4262 +3 4903 5023 4122 +3 4710 4918 4008 +3 4588 5322 4140 +3 3997 5322 4588 +3 4153 5311 4597 +3 4006 5007 4637 +3 4618 5233 300 +3 4251 5202 5008 +3 4583 5146 4002 +3 3854 5355 4563 +3 4563 5355 4135 +3 4967 4997 4105 +3 4841 5074 3934 +3 4066 4882 4759 +3 4194 5206 4573 +3 4103 5294 4587 +3 4199 5159 4861 +3 4720 4983 4246 +3 3986 4983 4720 +3 4141 4884 4785 +3 4785 4884 3952 +3 4076 5320 4756 +3 4406 5226 4674 +3 4605 5122 4376 +3 3941 5333 4805 +3 4599 5102 4131 +3 4123 5265 4569 +3 4132 5196 4582 +3 4844 4848 4117 +3 4168 5104 4606 +3 4210 5201 4979 +3 4926 5200 4262 +3 3898 5200 4926 +3 3978 5062 4620 +3 4092 4848 4844 +3 4084 5076 4925 +3 3965 5287 4574 +3 4920 5086 3873 +3 4205 5086 4920 +3 4941 4942 4185 +3 4080 4942 4941 +3 4105 5273 4587 +3 4861 5159 3789 +3 4713 4952 118 +3 3833 5290 5013 +3 5013 5290 4327 +3 4296 5156 4812 +3 4812 5156 3887 +3 3795 5048 4979 +3 4979 5048 4210 +3 4074 5010 4678 +3 4328 5093 4874 +3 4685 5217 4334 +3 4636 5225 4110 +3 4911 4959 3810 +3 4330 4959 4911 +3 4137 5260 4717 +3 4723 5131 3903 +3 4583 5277 3785 +3 3863 5306 5064 +3 4210 5048 4653 +3 5039 5237 4146 +3 4581 5348 4072 +3 4731 4953 4170 +3 4587 5273 3851 +3 4614 5186 4016 +3 4889 5141 4206 +3 315 5141 4889 +3 120 5346 4636 +3 4832 4962 4126 +3 3967 4962 4832 +3 4239 5123 4616 +3 5004 5070 4228 +3 3871 5070 5004 +3 4755 4968 4201 +3 3853 5268 4590 +3 4814 4894 4055 +3 4040 5227 4597 +3 4752 5071 4022 +3 4128 5071 4752 +3 4617 5129 4188 +3 4591 5290 3833 +3 4253 5264 4950 +3 4739 5222 4390 +3 4646 5246 4093 +3 5008 5202 3799 +3 3789 5159 4613 +3 4195 4956 4897 +3 3916 5072 4910 +3 4058 5087 4653 +3 4590 5356 3964 +3 4145 5195 4823 +3 4119 5266 4669 +3 251 5003 4722 +3 4593 5345 4065 +3 4153 5119 4810 +3 4810 5119 3965 +3 4651 5105 4165 +3 5181 5236 3853 +3 4859 5133 4129 +3 4635 5138 3918 +3 4898 5080 4181 +3 3907 5080 4898 +3 4688 5289 4323 +3 4843 5194 4085 +3 5027 5092 4115 +3 4242 5092 5027 +3 3995 5222 4739 +3 4983 5153 4246 +3 4127 5153 4983 +3 4984 5100 3781 +3 4221 5100 4984 +3 4110 5158 4636 +3 4106 5228 4964 +3 4061 5005 4746 +3 4386 5176 4737 +3 3815 5121 4807 +3 4936 5357 3846 +3 4170 5301 4731 +3 4731 5301 3900 +3 4847 5305 4169 +3 4805 5333 4198 +3 4718 5258 3871 +3 354 5269 4621 +3 4306 5270 4622 +3 4622 5270 326 +3 4621 5269 4305 +3 4147 5303 4684 +3 4868 5027 3800 +3 4242 5027 4868 +3 3786 5255 4623 +3 4825 4972 4061 +3 222 5095 4700 +3 4684 5303 4021 +3 3874 5092 5045 +3 5045 5092 4242 +3 3928 5041 4783 +3 4869 5178 4286 +3 4634 5307 3969 +3 4625 5286 3765 +3 4669 5155 4119 +3 3990 5203 4643 +3 4700 5095 4132 +3 289 5052 4728 +3 4617 5332 4158 +3 4277 5118 4842 +3 4625 5312 3989 +3 5088 5272 4232 +3 4686 5294 4103 +3 4513 5242 4821 +3 4767 5121 3815 +3 4134 5121 4767 +3 4173 4967 4909 +3 4118 5037 4875 +3 298 5113 4695 +3 4810 5311 4153 +3 4663 5257 3796 +3 4157 4978 4879 +3 4879 4978 3948 +3 4982 5049 3982 +3 4117 5307 4634 +3 4676 5187 292 +3 4804 5001 4066 +3 3860 5246 4646 +3 3981 5120 4697 +3 4094 5198 4671 +3 3872 5098 4942 +3 4942 5098 4185 +3 4156 5353 4631 +3 4909 5310 4173 +3 4852 5128 3983 +3 3870 5302 4815 +3 4815 5302 4197 +3 4658 5241 4266 +3 4320 5347 4633 +3 3826 5188 4683 +3 4712 5106 3830 +3 3806 5115 4747 +3 4118 5149 5037 +3 5037 5149 4250 +3 4687 5189 4077 +3 4636 5346 4279 +3 4985 5147 4221 +3 3902 5147 4985 +3 4173 5310 5184 +3 4989 5293 3842 +3 4281 5293 4989 +3 4111 5257 4663 +3 3962 5321 5292 +3 5292 5321 4434 +3 4138 5354 4705 +3 4208 5114 4992 +3 4992 5114 4156 +3 4887 4980 4380 +3 3811 4980 4887 +3 4288 5236 5181 +3 4783 5041 4115 +3 4764 5064 4159 +3 3831 5088 4742 +3 4746 5082 4061 +3 4261 5165 5051 +3 5051 5165 4150 +3 4351 5131 4839 +3 4839 5131 4086 +3 4078 5053 4878 +3 4727 5112 4054 +3 4912 5077 4164 +3 347 5077 4912 +3 4700 5244 4056 +3 4132 5244 4700 +3 4892 5234 4411 +3 4149 5234 4892 +3 4744 5094 3779 +3 3903 5044 4794 +3 4794 5044 4112 +3 4772 5334 4108 +3 4086 5131 4723 +3 5277 5352 4190 +3 4014 5096 4773 +3 4897 4956 4088 +3 3880 5105 4819 +3 3854 5207 4699 +3 5186 5274 4177 +3 4253 5110 4776 +3 4123 5235 4692 +3 4798 5351 3861 +3 4190 5351 4798 +3 4094 4985 4984 +3 4984 4985 4221 +3 4952 5346 119 +3 4279 5346 4952 +3 3884 5331 4885 +3 4768 5276 4045 +3 4858 5236 4090 +3 5193 5223 3799 +3 4335 5223 5193 +3 4909 4967 3899 +3 4686 5291 3899 +3 3899 5294 4686 +3 4838 5044 4351 +3 4112 5044 4838 +3 5040 5282 3797 +3 4286 5282 5040 +3 5118 5195 4145 +3 4152 5127 4999 +3 4999 5127 4222 +3 4719 5314 4517 +3 3773 5314 4719 +3 4095 5096 4778 +3 4902 5339 3838 +3 4108 5334 4817 +3 4793 5194 3785 +3 4737 5176 3994 +3 4708 5250 4297 +3 3875 5149 4795 +3 4110 5225 4827 +3 4242 5183 5045 +3 3894 5248 4788 +3 3889 5206 4921 +3 4921 5206 4194 +3 3901 5103 4899 +3 4899 5103 4155 +3 4087 4990 4989 +3 4989 4990 4281 +3 4808 5085 4036 +3 4862 5058 4353 +3 4902 5295 4076 +3 4748 5249 3840 +3 4332 5279 4711 +3 4837 5298 4072 +3 4808 5109 4304 +3 3838 5339 4711 +3 3942 5216 4954 +3 4954 5216 4250 +3 4184 5283 4859 +3 4859 5283 344 +3 4821 5242 3816 +3 3866 5240 4749 +3 4749 5240 4134 +3 4229 5074 4841 +3 4922 5264 4253 +3 4787 5292 4095 +3 4249 5145 4786 +3 4262 5336 4926 +3 4926 5336 4052 +3 3785 5194 4843 +3 4213 5285 5080 +3 5216 5243 4250 +3 4232 5098 4860 +3 4860 5098 3872 +3 4864 5266 4119 +3 4878 5053 4162 +3 4711 5322 3997 +3 4038 5264 4735 +3 3853 5236 4858 +3 4795 5149 4118 +3 4090 5236 4977 +3 4886 5203 4169 +3 3840 5249 4770 +3 4340 5318 4939 +3 4939 5318 4220 +3 3787 5169 4790 +3 3852 5153 4837 +3 4759 5319 3763 +3 3906 5260 4754 +3 4597 5311 4885 +3 4944 5057 140 +3 4923 5262 4438 +3 4188 5357 4723 +3 4322 5194 4793 +3 4842 5118 4145 +3 4263 5313 5111 +3 4055 5177 4814 +3 4874 5093 4104 +3 4817 5168 4108 +3 3777 5214 5139 +3 5139 5214 4282 +3 4881 5315 4280 +3 3874 5315 4881 +3 4770 5249 4125 +3 4903 5154 4466 +3 4063 5217 4789 +3 4148 5258 5085 +3 4021 5303 4753 +3 4200 5170 4824 +3 4337 5296 4836 +3 4910 5072 4104 +3 4207 5310 4909 +3 4837 5153 4127 +3 4107 5276 4768 +3 4301 5282 4846 +3 4136 5057 4944 +3 4823 5195 4268 +3 4756 5320 3792 +3 5125 5328 4166 +3 4788 5248 4113 +3 4344 5049 4982 +3 4130 5319 4759 +3 4158 5332 4794 +3 4794 5332 3903 +3 4129 5344 4961 +3 4834 5262 4054 +3 4963 5244 4582 +3 5135 5297 4311 +3 4175 5297 5135 +3 4139 5315 5045 +3 4904 5179 4281 +3 3973 5179 4904 +3 4052 5336 4763 +3 4144 5245 4815 +3 4815 5245 3870 +3 4794 5263 4158 +3 3871 5258 5070 +3 4827 5225 3887 +3 4042 5250 4818 +3 4262 5199 5151 +3 5151 5199 3805 +3 4865 5254 3807 +3 4016 5186 4928 +3 3907 5172 5080 +3 5080 5172 4213 +3 3925 5343 5038 +3 4122 5154 4903 +3 5107 5323 4287 +3 4225 5323 5107 +3 4133 5262 4834 +3 4880 5357 4188 +3 3846 5357 4880 +3 5097 5148 4171 +3 4207 5148 5097 +3 3870 5245 4845 +3 5098 5211 4185 +3 4232 5211 5098 +3 4203 5243 5216 +3 4250 5243 5037 +3 4912 5232 4443 +3 4166 5328 5199 +3 4809 5335 4152 +3 4216 5325 5144 +3 4853 5343 4486 +3 4318 5286 5103 +3 4104 5191 4910 +3 4964 5132 4106 +3 4817 5334 3798 +3 4836 5296 4274 +3 5212 5269 355 +3 4305 5269 5212 +3 325 5270 5213 +3 5213 5270 4306 +3 5116 5344 4129 +3 4054 5262 4923 +3 4846 5282 4286 +3 4127 5298 4837 +3 4970 5145 3797 +3 4113 5248 5136 +3 5136 5248 4315 +3 5051 5304 296 +3 4177 5204 4994 +3 4994 5204 3912 +3 3805 5328 5055 +3 5055 5328 4257 +3 4928 5186 4177 +3 5097 5310 4207 +3 3888 5266 4864 +3 3792 5241 4973 +3 3880 5220 5105 +3 4143 5343 4853 +3 145 5140 5046 +3 5046 5140 4175 +3 4164 5232 4912 +3 4200 5293 5179 +3 3984 5267 5031 +3 5179 5293 4281 +3 4898 5349 4060 +3 4181 5349 4898 +3 3893 5300 4882 +3 4076 5295 4883 +3 4968 5327 4201 +3 3984 5327 4968 +3 4979 5201 4135 +3 4885 5311 3884 +3 4964 5228 3770 +3 5045 5183 4139 +3 3922 5280 5065 +3 5065 5280 4272 +3 4056 5244 4963 +3 5064 5306 4159 +3 4977 5236 4288 +3 5172 5271 4213 +3 4258 5271 5172 +3 4262 5200 5199 +3 5199 5200 4166 +3 5184 5310 3886 +3 3885 5195 5118 +3 4135 5355 4914 +3 3904 5324 5125 +3 5125 5324 4257 +3 5037 5243 3791 +3 5204 5274 4294 +3 4961 5344 3859 +3 4200 5179 5170 +3 4217 5325 5065 +3 5065 5325 3922 +3 5031 5267 4215 +3 5170 5179 3973 +3 5105 5220 4165 +3 5070 5258 4148 +3 5209 5256 3958 +3 4238 5256 5209 +3 4150 5304 5051 +3 5045 5315 3874 +3 4257 5328 5125 +3 5080 5285 4181 +3 5223 5224 4154 +3 4335 5224 5223 +3 5038 5343 4143 +3 3886 5310 5097 +3 4232 5272 5211 +3 5211 5272 3953 +3 5111 5313 4176 +3 5241 5320 4266 +3 3792 5320 5241 +3 5351 5352 4339 +3 4190 5352 5351 +3 4177 5274 5204 +3 5341 5342 4163 +3 4430 5342 5341 +3 4379 5344 5116 +3 5144 5325 4217 +3 4257 5324 5280 +3 5280 5324 4272 +3 5199 5328 3805 +3 5229 5349 4181 +3 4467 5349 5229 +3 4711 5339 5322 +3 4160 5356 5268 +3 5268 5356 4590 +3 5322 5339 4140 +3 5864 5586 5924 +3 5680 5889 6369 +3 5889 5437 6369 +3 5949 5690 6287 +3 5481 5949 6287 +3 5761 5537 5960 +3 5846 5425 6084 +3 5578 5846 6084 +3 5849 5542 5890 +3 5732 5546 6059 +3 5635 5792 6595 +3 5781 5491 5920 +3 427 6204 6603 +3 447 5826 6097 +3 5745 6414 6708 +3 5506 6699 6751 +3 374 5 6147 +3 5 255 6147 +3 5364 5849 5890 +3 5388 5789 5983 +3 5808 5483 5936 +3 6294 5735 6692 +3 5546 5732 6080 +3 6002 5616 6051 +3 5394 6002 6051 +3 5546 5769 6478 +3 5820 5508 5902 +3 5365 5820 5902 +3 6699 5802 6751 +3 5550 5742 6079 +3 5584 5926 6007 +3 5926 5528 6007 +3 5821 5470 5930 +3 5862 5405 5955 +3 5835 5395 6265 +3 5771 5376 5976 +3 326 327 5875 +3 340 341 5975 +3 5829 5467 5913 +3 427 426 6204 +3 6128 5670 6326 +3 5941 6148 6522 +3 6093 5666 6386 +3 272 273 5869 +3 5491 5781 6185 +3 6223 5961 6276 +3 5879 5676 6398 +3 5444 5879 6398 +3 5797 5389 5927 +3 5791 5611 5938 +3 5453 5736 6120 +3 5837 5620 6393 +3 5556 5914 5928 +3 5914 5511 5928 +3 5848 5506 6751 +3 5751 396 6152 +3 5736 5453 6400 +3 5989 5689 6360 +3 5961 5587 6276 +3 5760 5446 6087 +3 5539 5760 6087 +3 5574 5950 6175 +3 5620 5837 6363 +3 5496 5792 6224 +3 5832 5410 5959 +3 5497 5776 6159 +3 5903 5511 6016 +3 5829 5406 5991 +3 5657 6025 6174 +3 5772 5532 6042 +3 5368 5933 6159 +3 5933 5628 6159 +3 5975 341 6111 +3 5642 5809 6436 +3 5799 5491 6185 +3 6592 5520 6831 +3 5421 5793 6001 +3 6099 5596 6145 +3 5502 6432 6465 +3 5862 5538 5900 +3 419 5948 6212 +3 5760 5539 6770 +3 5742 5550 6181 +3 5405 5862 5900 +3 5767 5507 5985 +3 5453 5990 6400 +3 5883 435 6065 +3 5397 5847 5974 +3 5588 5829 5913 +3 326 5875 6428 +3 5792 5496 5962 +3 5626 5859 6281 +3 6025 5433 6174 +3 328 329 5816 +3 5376 5771 6530 +3 5769 5546 6082 +3 5783 6294 6692 +3 5990 5734 6400 +3 6078 6623 6652 +3 6413 5532 6508 +3 5872 5528 6013 +3 5558 5872 6013 +3 5592 5745 6119 +3 5545 5852 5954 +3 5560 5821 5930 +3 5859 5468 6281 +3 5903 6016 6810 +3 5803 5521 6744 +3 424 5867 6356 +3 5509 5907 6213 +3 5532 6034 6508 +3 5814 5496 6224 +3 5765 5569 6601 +3 5570 5766 6600 +3 5806 5502 6465 +3 5745 5592 6754 +3 6414 5627 6708 +3 6175 5950 6620 +3 5900 5538 5916 +3 5845 5464 6578 +3 5399 5861 5934 +3 5861 5524 5934 +3 5941 5420 6148 +3 5529 5900 5916 +3 5779 6592 6831 +3 5793 5421 6029 +3 5531 5793 6029 +3 5515 5866 6613 +3 5818 5468 6554 +3 5675 5818 6554 +3 5830 5541 5947 +3 5958 5666 6093 +3 6038 5470 6544 +3 5491 5880 6489 +3 5792 5962 6595 +3 5553 5784 6135 +3 5500 5989 6360 +3 5837 5552 6047 +3 5414 5837 6047 +3 5869 273 6332 +3 5521 5803 6832 +3 411 5792 6389 +3 5401 5824 5969 +3 5523 5912 6049 +3 5775 5367 6667 +3 6 325 5891 +3 6050 5651 6090 +3 5429 6050 6090 +3 5943 5370 6240 +3 5541 6078 6652 +3 5609 5915 6180 +3 6143 5545 6248 +3 396 5751 6623 +3 5525 5776 6001 +3 5504 5834 6454 +3 5877 5452 6041 +3 5604 5877 6041 +3 5401 5801 6761 +3 5582 6189 6636 +3 5446 5760 6242 +3 5484 5846 5937 +3 5868 5521 6010 +3 5663 6052 6142 +3 6052 5369 6142 +3 5777 353 6205 +3 5941 5629 6186 +3 5420 5941 6186 +3 5870 5513 5919 +3 5390 5812 6167 +3 5441 5864 5924 +3 5470 6038 6442 +3 5520 5816 6898 +3 5507 5767 6097 +3 5846 5578 6392 +3 6168 260 6449 +3 5834 5504 5959 +3 5600 5834 5959 +3 5932 5515 6613 +3 5895 5624 6213 +3 5808 267 6161 +3 6265 5395 6661 +3 5827 5439 5965 +3 5504 5832 5959 +3 5506 5848 6409 +3 391 5854 6605 +3 5988 6578 6596 +3 5686 5988 6596 +3 5464 5845 6424 +3 5521 5868 6744 +3 5551 5853 6169 +3 5469 5789 6011 +3 438 437 5893 +3 6436 5809 6800 +3 5801 5460 6327 +3 5407 5942 6201 +3 5532 5772 6073 +3 5489 5805 6304 +3 5805 5605 6304 +3 5725 6243 6747 +3 419 418 5948 +3 5449 6067 6416 +3 369 6008 6419 +3 5520 5925 6831 +3 5815 5396 6694 +3 5832 5504 5966 +3 5789 5388 6546 +3 5827 5536 6109 +3 5531 5882 6063 +3 272 5869 6048 +3 5396 5822 6694 +3 5725 6086 6243 +3 6119 5745 6708 +3 5639 5875 5993 +3 5537 5761 6464 +3 5943 6240 6355 +3 5880 6302 6489 +3 5475 5849 6330 +3 5758 5567 6219 +3 5567 5758 6151 +3 5678 5845 6578 +3 5776 5525 6589 +3 5789 5612 6371 +3 5415 5876 5998 +3 5443 5836 6340 +3 5836 5625 6340 +3 5812 5390 5986 +3 454 5845 6560 +3 358 5786 6291 +3 5890 5509 6228 +3 5418 5985 6157 +3 5739 5972 6479 +3 5972 5385 6479 +3 5878 5487 5939 +3 5839 5398 6134 +3 5583 5790 6237 +3 5790 5468 6237 +3 265 266 5936 +3 5595 5917 6293 +3 5735 6294 6845 +3 5569 5765 6893 +3 5810 5517 6670 +3 5516 5858 5956 +3 6370 5982 6922 +3 5893 5504 6454 +3 5924 5586 6696 +3 5781 275 6185 +3 5885 5555 6328 +3 5535 5831 6367 +3 5361 5915 6195 +3 5866 5567 6542 +3 425 424 6356 +3 5392 5923 6409 +3 5923 5693 6409 +3 5424 5993 6182 +3 5509 6213 6453 +3 5891 325 6428 +3 5800 5423 6101 +3 5548 5800 6101 +3 5766 5570 6232 +3 5807 5431 6012 +3 5519 5807 6012 +3 5902 5562 6016 +3 5630 5838 6502 +3 5800 5515 6124 +3 5502 5806 6025 +3 5850 5709 6416 +3 6015 6552 6617 +3 5878 5361 5954 +3 5910 5521 6832 +3 5416 6006 6516 +3 5734 6235 6307 +3 5807 5656 6537 +3 5431 5807 6537 +3 5773 5460 6071 +3 5466 5837 6393 +3 5925 5520 6898 +3 265 5936 6469 +3 5822 5396 6045 +3 6118 5361 6195 +3 6001 5793 6719 +3 5969 5824 6870 +3 392 391 6605 +3 5490 5971 6177 +3 5777 5469 6806 +3 5926 5404 6013 +3 5902 6016 6863 +3 5390 5982 6370 +3 6016 5562 6810 +3 5831 5535 6860 +3 6031 5415 6126 +3 6201 5942 6304 +3 5524 5861 5977 +3 5367 5858 6667 +3 5495 5857 6210 +3 5409 5956 5977 +3 5710 6466 6675 +3 5379 6108 6114 +3 5837 5414 6363 +3 5866 5515 6823 +3 6430 6785 6913 +3 5609 6180 6346 +3 5517 5969 6870 +3 5900 5529 5981 +3 6059 5546 6478 +3 6096 5425 6206 +3 5890 5542 6910 +3 5986 5733 6519 +3 6095 5690 6204 +3 5599 6095 6204 +3 263 6089 6150 +3 5508 6015 6617 +3 5555 5885 6035 +3 5885 5358 6035 +3 5969 5626 6281 +3 5857 5495 6785 +3 5937 5846 6392 +3 5845 5640 6424 +3 5978 5602 6117 +3 5793 5531 6063 +3 5819 5553 6135 +3 6074 5401 6761 +3 5525 6001 6719 +3 6293 5917 6475 +3 5586 5884 6470 +3 6459 6085 6925 +3 5552 6154 6523 +3 417 6151 6593 +3 5398 5839 6651 +3 5839 5694 6651 +3 5810 5471 6312 +3 5774 5544 6555 +3 5360 6128 6326 +3 5707 5854 6689 +3 5854 5469 6689 +3 5783 5405 6294 +3 6032 5670 6128 +3 5583 5786 6461 +3 6785 5495 6913 +3 5847 5527 6748 +3 6096 6206 6665 +3 5572 6193 6242 +3 5389 5797 6497 +3 5858 5367 6026 +3 6831 5926 6907 +3 5792 411 6224 +3 5501 5986 6519 +3 5798 5580 6066 +3 6235 5588 6307 +3 448 447 6097 +3 5544 5774 6658 +3 6182 5993 6592 +3 5522 5944 6499 +3 5969 6281 6614 +3 5489 5883 6065 +3 5689 5989 6817 +3 5847 5397 6776 +3 5912 5523 6706 +3 5612 5789 6438 +3 5789 5469 6438 +3 5787 5564 6853 +3 5624 5895 6505 +3 5521 5965 6241 +3 5359 6030 6056 +3 6030 5606 6056 +3 5513 5870 6326 +3 5527 5856 6748 +3 5392 5848 6755 +3 6157 5985 6582 +3 5816 5520 6207 +3 6193 5728 6242 +3 6053 399 6642 +3 5404 5926 6831 +3 5812 5486 6167 +3 5536 5827 6685 +3 5860 5381 6141 +3 6077 5608 6310 +3 5884 5497 5980 +3 5826 5507 6097 +3 5365 5914 5964 +3 5914 5556 5964 +3 6102 5552 6523 +3 5825 5634 6092 +3 5394 6051 6063 +3 6077 6310 6452 +3 5654 5950 6253 +3 6067 5449 6458 +3 369 370 6008 +3 5525 5840 6589 +3 5509 5994 6228 +3 5611 5791 6442 +3 5568 5812 6345 +3 269 6382 6526 +3 6039 5419 6136 +3 5507 5826 6799 +3 6706 5523 6896 +3 435 434 6065 +3 6108 5644 6114 +3 5458 5785 6183 +3 6278 5522 6499 +3 5875 5520 5993 +3 5540 5785 6305 +3 5498 5865 6061 +3 6101 5663 6142 +3 5548 6101 6142 +3 5460 5773 6327 +3 6006 5715 6516 +3 6189 5698 6636 +3 6300 5847 6776 +3 5396 5815 6591 +3 5413 5939 6297 +3 6031 6126 6604 +3 6432 5720 6465 +3 5876 5514 5998 +3 5602 5978 6110 +3 5978 5576 6110 +3 5550 6583 6806 +3 5364 5785 6838 +3 5875 5639 6428 +3 5856 5527 6669 +3 5968 5485 6407 +3 5695 5968 6407 +3 5800 5548 6100 +3 6010 5521 6241 +3 455 454 6560 +3 6067 5697 6416 +3 6022 5810 6670 +3 5363 6022 6670 +3 5367 5775 6200 +3 5533 6085 6459 +3 5939 5413 6189 +3 5903 5397 5974 +3 6579 5979 6707 +3 5567 6151 6542 +3 6148 5650 6522 +3 5431 5813 6191 +3 5928 5511 6803 +3 5937 5371 6144 +3 6111 342 6673 +3 5778 5563 6270 +3 5786 5583 6280 +3 6792 5928 6803 +3 5514 5876 6009 +3 5841 5463 6379 +3 5615 5841 6379 +3 5649 6143 6248 +3 5753 6068 6550 +3 5563 5778 6267 +3 5400 5787 6460 +3 6039 5885 6328 +3 5809 5642 6500 +3 5465 5809 6500 +3 5469 5777 6689 +3 5491 5799 6585 +3 5506 6409 6655 +3 5411 5895 6213 +3 5405 5900 5981 +3 5533 6200 6446 +3 275 5781 6715 +3 5825 5503 6069 +3 5776 5497 6353 +3 5519 6076 6864 +3 5605 5805 6107 +3 5376 5997 6274 +3 5997 5665 6274 +3 353 5777 6583 +3 6382 5782 6526 +3 5368 5840 6215 +3 5840 5581 6215 +3 5607 5869 6332 +3 341 342 6111 +3 5423 5800 6124 +3 5790 5583 6166 +3 5792 5635 6389 +3 5785 5540 6183 +3 6273 5438 6298 +3 5656 5807 6108 +3 5510 5892 5995 +3 5535 5957 6860 +3 5922 5550 6011 +3 5961 5402 6088 +3 5587 5961 6088 +3 5443 5853 6036 +3 5550 6079 6583 +3 5405 5783 6366 +3 5801 5401 6190 +3 5563 5801 6190 +3 6200 5775 6446 +3 6670 5517 6870 +3 5918 5374 6488 +3 5689 5918 6488 +3 5589 5877 6292 +3 5670 6214 6608 +3 5948 5589 6212 +3 331 6295 6601 +3 6296 432 6600 +3 5824 5401 6074 +3 5489 6065 6456 +3 5884 5980 6470 +3 5812 5568 6540 +3 5652 6048 6341 +3 5962 5496 6209 +3 6204 426 6356 +3 6076 5870 6864 +3 5839 6134 6403 +3 452 451 5897 +3 5564 5787 6226 +3 5580 5798 6919 +3 6394 5526 6746 +3 5785 5364 6305 +3 5784 5553 6236 +3 438 5893 6454 +3 5787 5400 6226 +3 5529 5916 6796 +3 5861 6394 6746 +3 5807 5519 6521 +3 6214 5815 6608 +3 258 259 5952 +3 6177 5971 6691 +3 5359 6009 6104 +3 5438 6032 6298 +3 6047 5552 6102 +3 5614 6047 6102 +3 5785 5458 6276 +3 5879 5444 6154 +3 6069 5426 6892 +3 5528 5872 6165 +3 426 425 6356 +3 5842 5566 6524 +3 5537 6093 6386 +3 5970 5384 6451 +3 5786 358 6461 +3 6657 5554 6799 +3 6426 6019 6553 +3 5816 329 6162 +3 5858 6026 6766 +3 6026 5524 6766 +3 5916 6153 6796 +3 5874 5532 6073 +3 5471 5810 6367 +3 5539 5991 6770 +3 5805 5489 6456 +3 439 5834 6286 +3 5906 389 6299 +3 5468 5790 6554 +3 6049 5912 6309 +3 5429 6099 6145 +3 5532 5874 6034 +3 5746 6071 6633 +3 5922 5388 6671 +3 5741 5922 6671 +3 6341 6048 6944 +3 6068 5530 6550 +3 5505 5979 6579 +3 5791 6336 6798 +3 5539 5820 6317 +3 5982 5390 6167 +3 6295 5765 6601 +3 5766 6296 6600 +3 6188 5710 6210 +3 5456 6188 6210 +3 5855 5538 6722 +3 5849 6106 6330 +3 5520 5875 6207 +3 6151 5758 6593 +3 5553 5819 6220 +3 5963 5573 5998 +3 5514 5963 5998 +3 5838 5472 6082 +3 6066 5696 6627 +3 5379 6114 6702 +3 5561 5814 6130 +3 6114 5850 6702 +3 5645 5987 6255 +3 6336 5375 6798 +3 5834 439 6454 +3 5860 5518 6058 +3 5426 6069 6323 +3 5929 5414 6047 +3 5614 5929 6047 +3 5538 5862 6722 +3 6039 6136 6550 +3 5664 6168 6449 +3 5801 5563 6267 +3 5511 5903 6803 +3 5979 5726 6115 +3 5644 6005 6046 +3 5881 5665 6534 +3 5458 5881 6534 +3 5930 5470 6581 +3 5798 6066 6627 +3 5836 5443 6611 +3 5509 5890 6910 +3 6669 5527 6763 +3 6108 5807 6521 +3 5972 5706 6049 +3 5385 5972 6049 +3 5898 5377 6064 +3 5406 5829 6290 +3 5829 5588 6290 +3 6623 5751 6652 +3 6008 5661 6419 +3 5358 5885 6531 +3 5557 5808 6161 +3 5497 6159 6319 +3 5868 5676 6618 +3 5644 6108 6521 +3 5987 5378 6255 +3 5515 5800 6482 +3 5862 5955 6514 +3 6022 5535 6367 +3 5838 6082 6502 +3 5530 5885 6039 +3 6567 5459 6652 +3 5639 5891 6428 +3 5558 5898 6064 +3 5709 5850 6663 +3 5868 6618 6744 +3 5919 5409 6005 +3 379 378 5967 +3 5569 6162 6601 +3 6163 5570 6600 +3 5460 5801 6267 +3 5888 5480 6721 +3 5809 5465 6440 +3 5859 5626 6433 +3 5909 5507 6799 +3 6618 5466 6744 +3 5529 6164 6836 +3 5764 6370 6922 +3 5749 6374 6813 +3 6416 5709 6780 +3 5654 6253 6530 +3 6024 5596 6099 +3 5483 5808 6283 +3 400 399 6053 +3 5894 5643 6452 +3 412 411 6389 +3 5848 6060 6755 +3 5644 6046 6876 +3 5907 5509 6910 +3 6451 5384 6684 +3 5956 5409 6020 +3 6089 5650 6148 +3 5591 6089 6148 +3 5992 5494 6751 +3 5802 5992 6751 +3 5542 5849 6541 +3 414 413 5932 +3 5511 5914 6016 +3 5521 5910 6685 +3 5537 6464 6647 +3 5571 5833 6243 +3 5849 5364 6106 +3 5852 5545 6143 +3 5498 6061 6940 +3 5833 349 6599 +3 5541 5830 6137 +3 5503 5825 6518 +3 6002 5394 6710 +3 5978 6117 6434 +3 5394 6350 6710 +3 5821 5560 6568 +3 5360 5870 6076 +3 6297 5939 6548 +3 5840 5368 6589 +3 267 5808 6717 +3 5486 5812 6540 +3 5528 5926 6013 +3 5916 5538 6144 +3 5496 5814 6316 +3 5908 5523 6028 +3 5417 5874 6073 +3 6164 5873 6836 +3 6029 5606 6030 +3 5531 6029 6030 +3 6122 5581 6261 +3 5786 6280 6455 +3 5813 5431 6537 +3 5903 5974 6803 +3 6197 5601 6483 +3 328 5816 6207 +3 5409 5919 6020 +3 5923 5500 6017 +3 5917 5595 6021 +3 5642 6014 6229 +3 6014 5571 6229 +3 5827 5965 6685 +3 6063 6051 6719 +3 5907 5542 6075 +3 5773 6498 6607 +3 263 264 6089 +3 5740 6053 6642 +3 5729 5921 6377 +3 5542 6541 6558 +3 6575 5575 6874 +3 5833 5571 6271 +3 6044 5757 6200 +3 6061 5887 6940 +3 6441 456 6560 +3 271 272 6048 +3 5921 5667 6377 +3 5370 5892 6342 +3 6072 5554 6657 +3 258 5952 6506 +3 5560 5930 6179 +3 6113 363 6270 +3 5808 5557 6283 +3 6312 5471 6602 +3 5517 5810 6312 +3 5825 6069 6892 +3 349 5833 6271 +3 5436 5938 6313 +3 6211 5738 6252 +3 5382 6211 6252 +3 5913 5467 6580 +3 5880 5547 6257 +3 5388 5983 6557 +3 6464 5832 6647 +3 5399 5909 6057 +3 5909 5554 6057 +3 5858 5516 6667 +3 363 364 6270 +3 6065 5701 6456 +3 6280 5459 6455 +3 5923 6852 6901 +3 5552 5837 6481 +3 5965 5521 6685 +3 5544 5874 6555 +3 6200 5757 6775 +3 5691 5930 6581 +3 5902 5508 6917 +3 5983 5789 6371 +3 5882 5531 6758 +3 5604 5828 6199 +3 5417 5931 6743 +3 5426 5852 6143 +3 5814 5561 6316 +3 6196 5724 6458 +3 5779 6831 6907 +3 5397 5903 6916 +3 5459 5947 6652 +3 5510 6019 6426 +3 5470 5821 6544 +3 5519 6012 6076 +3 6365 5681 6413 +3 6169 5853 6343 +3 5468 5818 6281 +3 5818 5675 6528 +3 5874 5544 6718 +3 5415 5998 6126 +3 5439 5827 6759 +3 5937 6144 6644 +3 5841 5555 6250 +3 5936 5650 6469 +3 5853 5551 6551 +3 5508 5820 6320 +3 5820 5539 6448 +3 5820 5365 6317 +3 5854 5707 6605 +3 402 401 5984 +3 5873 5559 6836 +3 5923 5392 6852 +3 5845 5678 6560 +3 5518 5860 6141 +3 5362 5979 6115 +3 5891 5639 6802 +3 5619 6331 6760 +3 5996 5698 6260 +3 5393 5880 6257 +3 5838 5630 6510 +3 5467 5829 6485 +3 6071 5460 6633 +3 6062 5418 6749 +3 5634 5825 6892 +3 333 334 5951 +3 5880 5491 6585 +3 5679 6067 6458 +3 6070 5597 6390 +3 5400 5953 6482 +3 5483 5851 6176 +3 6060 5848 6751 +3 5494 6060 6751 +3 5571 6086 6229 +3 6383 366 6420 +3 5853 5443 6619 +3 5826 447 6657 +3 5434 5887 6473 +3 5887 5647 6473 +3 5567 5866 6823 +3 5945 5688 6768 +3 6115 5726 6699 +3 5410 5832 6464 +3 5425 5846 6206 +3 5580 5992 6139 +3 5694 5839 6850 +3 6027 5592 6096 +3 5579 6027 6096 +3 5705 6459 6925 +3 5881 5458 6183 +3 5875 327 6207 +3 5597 6247 6390 +3 5837 5466 6481 +3 5968 5662 6406 +3 5851 5483 6283 +3 5399 6057 6394 +3 6057 5709 6394 +3 6303 5736 6450 +3 5545 5921 6248 +3 5399 5934 6664 +3 5934 5716 6664 +3 5849 5475 6541 +3 6252 5911 6630 +3 5976 5376 6274 +3 417 416 6151 +3 5894 6452 6789 +3 5487 5878 6745 +3 5588 5913 6307 +3 267 268 6161 +3 5485 5968 6406 +3 5545 5954 6351 +3 5799 6105 6585 +3 6105 5547 6585 +3 5843 5617 6397 +3 5862 6514 6722 +3 5829 5991 6485 +3 5828 5604 6354 +3 6466 5420 6675 +3 5835 5493 6637 +3 5801 6327 6761 +3 5841 5615 6471 +3 5658 6252 6630 +3 5674 5913 6580 +3 5522 5975 6111 +3 5411 5907 6075 +3 5933 5495 6837 +3 5863 5490 6177 +3 5939 6189 6812 +3 5377 5898 6824 +3 5493 5835 6265 +3 5834 5600 6286 +3 5472 5838 6411 +3 285 5842 6524 +3 5769 6082 6805 +3 6003 5721 6310 +3 5966 5407 6093 +3 5967 378 6634 +3 5997 5574 6223 +3 5600 5888 6543 +3 5469 6011 6806 +3 5463 5841 6250 +3 6539 6170 6738 +3 5418 6062 6445 +3 5995 5419 6471 +3 5617 5843 6549 +3 5931 6617 6743 +3 5542 5907 6910 +3 5581 5840 6680 +3 5413 5873 6164 +3 6089 5591 6150 +3 5872 5412 6165 +3 5687 6654 6924 +3 5954 5852 6745 +3 5854 391 6227 +3 5395 5835 6322 +3 5513 6326 6608 +3 377 376 5988 +3 6852 5762 6901 +3 5625 5836 6350 +3 5409 5977 6046 +3 5362 6115 6538 +3 5840 5525 6404 +3 5552 5879 6154 +3 5940 5595 6230 +3 5480 5940 6230 +3 5859 6433 6790 +3 5938 5611 6313 +3 456 455 6560 +3 5917 5474 6477 +3 5656 5917 6477 +3 5846 5484 6764 +3 5631 6361 6736 +3 5640 5845 6285 +3 5845 454 6285 +3 6541 5795 6558 +3 6109 5536 6854 +3 5842 285 6493 +3 5770 6123 6681 +3 5962 6209 6412 +3 5708 6197 6483 +3 389 388 6299 +3 256 257 6004 +3 5566 5842 6381 +3 5555 5841 6328 +3 5364 6228 6305 +3 5490 5863 6381 +3 5990 5453 6563 +3 5879 5552 6481 +3 6074 5594 6263 +3 5575 6172 6874 +3 6515 393 6605 +3 5865 5498 6628 +3 5562 5902 6917 +3 5886 5568 6897 +3 5898 5558 6828 +3 6228 5744 6305 +3 5973 5432 6654 +3 5527 5847 6300 +3 5843 6109 6854 +3 5848 5392 6409 +3 6120 5569 6893 +3 5812 5986 6345 +3 5474 5917 6839 +3 5892 5370 6765 +3 5365 5902 6863 +3 6138 5888 6721 +3 5920 5414 6357 +3 6043 5372 6216 +3 6607 5380 6820 +3 6514 5481 6722 +3 5974 5847 6556 +3 6378 5995 6471 +3 5877 5589 6318 +3 5452 5877 6318 +3 5468 5859 6237 +3 5975 5522 6278 +3 5621 5975 6278 +3 6063 5882 6562 +3 5538 5855 6865 +3 6104 6009 6709 +3 5883 5489 6791 +3 405 404 6003 +3 5493 5996 6260 +3 5730 5999 6338 +3 5523 5908 6896 +3 6139 5992 6942 +3 5579 5860 6359 +3 5938 5436 6725 +3 5381 5860 6262 +3 5860 5579 6262 +3 6125 5633 6440 +3 5449 6196 6458 +3 5469 5854 6438 +3 6018 5373 6132 +3 5590 6018 6132 +3 6192 5945 6768 +3 5826 6657 6799 +3 5852 5426 6323 +3 6770 6192 6858 +3 6099 5429 6308 +3 5872 5558 6314 +3 5936 5483 6522 +3 5651 6050 6217 +3 5766 6232 6564 +3 385 5871 6368 +3 6123 5770 6418 +3 5977 5956 6766 +3 6037 5518 6141 +3 5630 6037 6141 +3 5868 6010 6737 +3 5610 5976 6274 +3 5866 415 6613 +3 5882 5625 6562 +3 5944 5522 6083 +3 5431 6191 6365 +3 6005 5409 6046 +3 5700 5990 6563 +3 5811 6115 6655 +3 6115 5506 6655 +3 5994 5448 6679 +3 5744 5994 6679 +3 5358 6531 6754 +3 5911 5553 6220 +3 415 5866 6542 +3 452 5897 6149 +3 353 354 6205 +3 5369 5901 6140 +3 5712 5899 6762 +3 5899 5477 6762 +3 6134 5549 6403 +3 5952 5657 6506 +3 6125 6440 6529 +3 5931 5562 6917 +3 5479 5972 6284 +3 5897 451 6238 +3 5871 5598 6368 +3 5884 5586 6288 +3 5983 5677 6557 +3 347 348 6014 +3 5895 5411 6311 +3 5598 5895 6311 +3 5871 385 6643 +3 5984 5549 6133 +3 6568 5560 6709 +3 6374 5457 6813 +3 6217 5755 6348 +3 5380 6217 6348 +3 5564 6041 6853 +3 5676 5879 6618 +3 5586 5864 6288 +3 5869 5607 6266 +3 357 358 6291 +3 6036 5535 6429 +3 5772 6042 6916 +3 6100 5400 6482 +3 5503 5987 6069 +3 5919 5513 6927 +3 5746 6383 6420 +3 6229 6086 6750 +3 5419 6328 6471 +3 6142 5798 6627 +3 5602 6064 6117 +3 6064 5377 6117 +3 5892 5510 6342 +3 5713 6104 6179 +3 5495 6210 6837 +3 5957 5551 6612 +3 5576 6195 6251 +3 6292 5877 6752 +3 5861 5399 6394 +3 5406 6192 6770 +3 6123 5540 6681 +3 5906 5477 6371 +3 5612 5906 6371 +3 5874 5417 6555 +3 5791 5938 6336 +3 5864 5441 6474 +3 5825 6092 6518 +3 5677 5983 6492 +3 5983 5477 6492 +3 5957 5535 6551 +3 6069 5645 6323 +3 5526 6394 6663 +3 5531 6030 6758 +3 5499 5970 6451 +3 5867 424 6486 +3 6013 5404 6450 +3 5876 5415 6568 +3 5566 6055 6524 +3 5992 5580 6734 +3 5973 5499 6451 +3 5681 6042 6413 +3 6075 5677 6492 +3 6178 5933 6837 +3 5698 5996 6636 +3 6498 5651 6607 +3 5738 5911 6252 +3 5987 5645 6069 +3 6204 5690 6603 +3 5547 5880 6585 +3 5981 5529 6836 +3 5407 5958 6093 +3 5364 5890 6228 +3 5507 5909 6934 +3 6030 6735 6758 +3 5405 5981 6294 +3 5827 6109 6399 +3 5952 259 6168 +3 5734 5990 6235 +3 6792 5752 6877 +3 5665 5881 6687 +3 402 5984 6133 +3 5873 5413 6297 +3 5928 5403 6476 +3 5867 5599 6356 +3 5752 6127 6877 +3 5877 5604 6752 +3 5870 5360 6326 +3 5599 5867 6421 +3 5914 5365 6863 +3 396 395 6152 +3 5876 6568 6709 +3 5676 5868 6737 +3 5618 5904 6411 +3 5904 5472 6411 +3 6331 5727 6760 +3 5740 6137 6520 +3 6155 5618 6410 +3 6433 5383 6790 +3 6027 5427 6937 +3 5371 5916 6144 +3 5361 5878 6666 +3 5659 6038 6544 +3 5998 5573 6126 +3 5559 5873 6501 +3 5976 5485 6406 +3 5771 5976 6406 +3 5718 6160 6346 +3 6160 5609 6346 +3 5632 6053 6520 +3 5548 6142 6627 +3 6045 5516 6842 +3 5822 6045 6842 +3 5559 5981 6836 +3 5878 5954 6745 +3 5984 401 6395 +3 5673 5881 6570 +3 6349 5864 6474 +3 5773 6071 6498 +3 5966 5504 6443 +3 5686 5967 6634 +3 5692 6579 6707 +3 6364 5424 6656 +3 5736 6400 6828 +3 6160 5718 6704 +3 5598 5871 6439 +3 5606 6349 6474 +3 6260 5698 6334 +3 6906 6027 6937 +3 5557 6170 6539 +3 5619 6122 6261 +3 5917 6021 6839 +3 6704 5718 6741 +3 5881 5673 6545 +3 5916 5371 6153 +3 5412 5872 6683 +3 5953 5567 6823 +3 6052 5663 6282 +3 5512 6052 6282 +3 5553 5911 6862 +3 5911 5738 6862 +3 5880 5393 6302 +3 5667 6245 6377 +3 5565 6008 6827 +3 260 261 6449 +3 5959 5410 6372 +3 6155 6410 6641 +3 6791 5593 6835 +3 5931 5417 6396 +3 5972 5739 6284 +3 372 373 6197 +3 5655 6012 6365 +3 6012 5431 6365 +3 5666 5958 6518 +3 5958 5503 6518 +3 5404 6303 6450 +3 5671 5996 6265 +3 5996 5493 6265 +3 5577 5892 6765 +3 6232 5454 6564 +3 6012 5655 6076 +3 5593 5893 6244 +3 5893 437 6244 +3 435 5883 6835 +3 5419 5995 6779 +3 5901 5369 6756 +3 5625 5882 6415 +3 6308 5429 6646 +3 393 392 6605 +3 6074 6263 6757 +3 5433 6024 6511 +3 422 421 6059 +3 6400 5898 6828 +3 5546 6080 6502 +3 5568 5935 6218 +3 6056 5606 6474 +3 6100 5548 6930 +3 5480 5888 6373 +3 5888 5600 6373 +3 6080 5732 6292 +3 8 356 6401 +3 394 8 6401 +3 6082 5472 6805 +3 6075 6492 6928 +3 5915 5582 6180 +3 5548 6627 6930 +3 6103 336 6193 +3 5754 6312 6602 +3 5782 6382 6405 +3 6328 5841 6471 +3 6071 5746 6888 +3 5629 5941 6176 +3 5941 5483 6176 +3 6135 5784 6826 +3 6084 5627 6645 +3 269 270 6382 +3 5437 5889 6277 +3 6137 5451 6520 +3 361 362 6203 +3 5926 5584 6907 +3 5500 5923 6901 +3 6172 5747 6430 +3 5455 6172 6430 +3 6002 5543 6094 +3 5892 5577 6779 +3 5915 5609 6195 +3 5428 6158 6346 +3 6158 5718 6346 +3 5554 5909 6799 +3 6198 6616 6794 +3 5907 5411 6213 +3 5823 6670 6870 +3 5568 5886 6540 +3 5927 5389 6504 +3 5648 6426 6553 +3 5550 5922 6181 +3 5910 6832 6932 +3 6167 5486 6494 +3 367 368 6033 +3 5432 5973 6738 +3 5446 6242 6301 +3 6242 5728 6301 +3 5885 5530 6531 +3 6115 5811 6538 +3 6347 5632 6520 +3 5953 5400 6460 +3 5682 6198 6247 +3 6198 5435 6247 +3 5396 6123 6418 +3 5485 6272 6407 +3 5687 5973 6654 +3 5933 5368 6912 +3 5495 5933 6913 +3 6483 5433 6511 +3 5497 5884 6353 +3 5628 5933 6178 +3 5596 6054 6145 +3 5626 5969 6352 +3 5969 5517 6352 +3 5733 5986 6736 +3 5693 5923 6588 +3 5632 6347 6403 +3 6347 5839 6403 +3 5997 6223 6534 +3 5818 6190 6614 +3 6190 5401 6614 +3 5607 6715 6787 +3 5688 5945 6653 +3 5945 5488 6653 +3 5580 6140 6734 +3 5774 6555 6743 +3 5621 6278 6638 +3 5650 5936 6522 +3 6020 5919 6927 +3 5373 6018 6275 +3 6018 5680 6275 +3 5366 5960 6869 +3 5593 5942 6268 +3 5942 5407 6268 +3 6229 5794 6500 +3 5642 6229 6500 +3 5870 5919 6864 +3 336 337 6193 +3 6272 5774 6407 +3 5804 6669 6763 +3 5639 5993 6587 +3 5408 6139 6942 +3 5489 5942 6791 +3 5535 6036 6551 +3 6832 5393 6932 +3 275 276 6185 +3 5647 5887 6606 +3 5921 5729 6855 +3 5575 6050 6145 +3 5616 6002 6814 +3 5950 5574 6253 +3 6044 5461 6706 +3 5757 6044 6706 +3 5434 5911 6220 +3 6054 5575 6145 +3 336 6103 6878 +3 6310 5721 6882 +3 6006 5484 6644 +3 5715 6006 6644 +3 5545 6351 6700 +3 6178 5710 6675 +3 5887 5434 6462 +3 5360 6034 6128 +3 6382 5652 6405 +3 6180 5582 6636 +3 5996 5428 6636 +3 281 282 6098 +3 6092 5666 6518 +3 5627 6322 6645 +3 6171 5370 6342 +3 335 336 6878 +3 5889 5680 6586 +3 5492 5905 6507 +3 5927 5496 6316 +3 5949 428 6603 +3 6036 6429 6705 +3 5967 5686 6628 +3 5498 5967 6628 +3 6006 5416 6512 +3 5496 5927 6209 +3 5565 6024 6099 +3 6044 5533 6459 +3 6156 5565 6827 +3 6654 5817 6924 +3 6191 5681 6365 +3 6098 5682 6247 +3 5597 6098 6247 +3 6 5891 6493 +3 5402 5961 6175 +3 5961 5574 6175 +3 5810 6022 6367 +3 6023 5501 6519 +3 5406 5945 6192 +3 5703 6111 6673 +3 375 9 6441 +3 9 456 6441 +3 6345 5501 6936 +3 6080 6423 6502 +3 6307 5913 6571 +3 5569 6303 6898 +3 5711 5955 6733 +3 5955 5570 6733 +3 377 5988 6634 +3 5667 6118 6245 +3 5683 6023 6519 +3 6006 5618 6155 +3 5484 6006 6155 +3 6106 5364 6838 +3 5643 5894 6615 +3 6303 5925 6898 +3 5893 5593 6443 +3 277 278 6105 +3 6202 5658 6630 +3 6208 5687 6924 +3 6342 5510 6426 +3 389 5906 6573 +3 6127 5752 6556 +3 5478 6127 6556 +3 5751 6567 6652 +3 5448 5994 6333 +3 5935 6345 6936 +3 5955 5405 6366 +3 6166 5583 6461 +3 6040 5512 6282 +3 5636 6040 6282 +3 5972 5479 6811 +3 6037 5422 6199 +3 5504 5893 6443 +3 5368 6159 6589 +3 6159 5776 6589 +3 423 6478 6486 +3 6250 5555 6819 +3 5576 6118 6195 +3 6016 5914 6863 +3 6110 5576 6251 +3 5516 6594 6667 +3 5882 6758 6856 +3 6004 5657 6174 +3 283 284 6055 +3 5950 5654 6529 +3 5465 5950 6529 +3 6136 5419 6779 +3 5533 6044 6200 +3 5899 5712 6753 +3 5441 5924 6249 +3 5506 6115 6699 +3 5547 6091 6257 +3 5964 5556 6325 +3 5906 5612 6573 +3 5908 5585 6650 +3 5895 5598 6439 +3 6473 6202 6630 +3 5958 5407 6201 +3 440 439 6286 +3 5477 5906 6762 +3 439 438 6454 +3 5585 5908 6900 +3 6042 5397 6916 +3 5685 5982 6167 +3 5632 5984 6395 +3 5622 6260 6334 +3 333 5951 6517 +3 5558 6013 6450 +3 5599 5904 6894 +3 5516 5956 6842 +3 6169 5894 6868 +3 5551 6169 6868 +3 5986 5390 6736 +3 5918 5689 6249 +3 5947 5459 6911 +3 5699 6052 6604 +3 6003 404 6732 +3 5424 6182 6656 +3 6556 5847 6748 +3 6028 5418 6900 +3 5920 5491 6489 +3 5479 5897 6408 +3 5889 6250 6819 +3 5781 5920 6787 +3 6802 5490 6833 +3 5581 6112 6261 +3 6139 5408 6467 +3 5719 6139 6467 +3 5590 6132 6233 +3 5584 6007 6171 +3 6007 5370 6171 +3 5573 5963 6755 +3 5544 6032 6128 +3 5915 5361 6666 +3 5425 6096 6119 +3 6096 5592 6119 +3 5730 6338 6841 +3 6073 5772 6396 +3 5897 5479 6565 +3 5571 6014 6271 +3 5607 6332 6715 +3 6216 5372 6354 +3 6140 5580 6919 +3 6007 5528 6677 +3 6002 6094 6814 +3 6041 5564 6216 +3 5604 6041 6216 +3 6059 421 6723 +3 411 410 6224 +3 6025 5806 6254 +3 6018 5590 6337 +3 379 5967 6222 +3 6583 5777 6806 +3 6068 5753 6875 +3 5943 5577 6765 +3 5956 6020 6842 +3 6306 6056 6474 +3 5986 5501 6345 +3 5367 6200 6775 +3 6187 5590 6233 +3 5929 5614 6437 +3 5482 5929 6437 +3 6179 5930 6513 +3 5991 5722 6485 +3 6243 5462 6747 +3 5999 280 6566 +3 5574 5997 6253 +3 6102 5374 6208 +3 5614 6102 6208 +3 5477 5899 6492 +3 5773 6607 6820 +3 5934 5524 6660 +3 277 6105 6887 +3 5371 5937 6392 +3 5761 5960 6388 +3 5574 5961 6223 +3 6045 5396 6418 +3 5988 5686 6634 +3 5486 6540 6809 +3 446 445 6072 +3 5415 6417 6568 +3 5883 6791 6835 +3 6361 5733 6736 +3 6120 5736 6303 +3 5524 5977 6766 +3 6036 5853 6551 +3 372 6197 6730 +3 6000 6624 6846 +3 403 402 6133 +3 5904 5599 6421 +3 6612 5551 6868 +3 6325 5556 6631 +3 5912 5647 6309 +3 5965 5439 6241 +3 5576 5978 6245 +3 6141 5381 6510 +3 428 5949 6468 +3 5662 5944 6533 +3 5403 5928 6792 +3 6000 5672 6624 +3 5943 5492 6507 +3 6465 5386 6662 +3 5573 6060 6740 +3 5575 6054 6339 +3 5472 5904 6421 +3 5909 5399 6664 +3 6341 5482 6437 +3 5817 6341 6437 +3 5601 6004 6174 +3 6313 5611 6497 +3 6462 5434 6829 +3 398 397 6078 +3 5929 5482 6266 +3 6187 5702 6688 +3 5946 5371 6392 +3 5904 5618 6512 +3 5493 5946 6637 +3 351 352 6079 +3 5742 6181 6610 +3 5905 5492 6547 +3 6452 5450 6789 +3 6159 5628 6319 +3 5433 6025 6254 +3 5702 6447 6688 +3 5878 5939 6812 +3 6164 5529 6796 +3 6439 5473 6505 +3 5895 6439 6505 +3 5946 5493 6487 +3 6198 5566 6616 +3 6005 5519 6864 +3 5971 5490 6802 +3 6217 6050 6575 +3 349 350 6599 +3 5721 6003 6732 +3 6075 5542 6558 +3 6186 5629 6319 +3 5797 6313 6497 +3 6230 5595 6293 +3 5697 6230 6293 +3 6396 5772 6810 +3 5516 6045 6594 +3 5854 6227 6438 +3 5737 6129 6815 +3 5830 5947 6385 +3 5714 6017 6360 +3 5920 6357 6787 +3 5819 6135 6926 +3 5923 6017 6588 +3 6050 5429 6145 +3 6329 5886 6897 +3 5655 6365 6413 +3 5911 5434 6630 +3 6227 5612 6438 +3 340 5975 6387 +3 5953 5515 6482 +3 5713 6179 6856 +3 5759 6134 6612 +3 6134 5398 6612 +3 6278 5748 6638 +3 5919 6005 6864 +3 5932 413 6572 +3 6017 5500 6360 +3 6158 6547 6880 +3 338 339 6116 +3 444 443 6259 +3 6067 5480 6230 +3 5697 6067 6230 +3 6256 5649 6269 +3 5752 6792 6803 +3 6218 5935 6937 +3 5427 6218 6937 +3 5582 5915 6666 +3 6091 6822 6841 +3 6114 5526 6663 +3 5850 6114 6663 +3 6126 5699 6604 +3 6696 5499 6771 +3 6772 6184 6895 +3 6144 5715 6644 +3 5549 5984 6403 +3 5984 5632 6403 +3 5945 5406 6290 +3 5391 5968 6552 +3 6134 5759 6146 +3 5434 6220 6829 +3 5505 6772 6895 +3 5417 6073 6396 +3 5418 6157 6900 +3 5942 5593 6791 +3 6052 5512 6604 +3 6091 5547 6822 +3 6734 5901 6740 +3 5430 6000 6331 +3 5414 5920 6363 +3 5942 5489 6304 +3 6478 5769 6486 +3 5647 5912 6941 +3 5458 6223 6276 +3 259 260 6168 +3 5924 6696 6771 +3 5667 5921 6700 +3 5921 5545 6700 +3 5403 6248 6855 +3 6248 5921 6855 +3 6417 5821 6568 +3 5913 5674 6571 +3 409 408 6130 +3 5540 6305 6681 +3 355 7 6515 +3 7 393 6515 +3 262 263 6150 +3 5374 5918 6621 +3 6292 5732 6929 +3 5427 6027 6359 +3 5407 5966 6268 +3 5922 5741 6714 +3 5994 5744 6228 +3 6058 5518 6598 +3 5978 5442 6245 +3 5939 5487 6548 +3 6010 5362 6737 +3 5414 5929 6357 +3 5732 6059 6723 +3 5938 5643 6336 +3 5755 6575 6874 +3 5990 5488 6235 +3 5361 6118 6351 +3 6118 5667 6351 +3 5989 5603 6306 +3 5441 5989 6306 +3 5515 5932 6713 +3 5935 5568 6345 +3 5891 6802 6833 +3 5973 5687 6711 +3 5499 5973 6711 +3 6066 5580 6427 +3 5990 5700 6712 +3 5488 5990 6712 +3 6105 5799 6887 +3 5917 5656 6475 +3 5485 5976 6272 +3 5515 5953 6823 +3 5419 6039 6328 +3 6203 362 6676 +3 5388 5922 6546 +3 5960 5366 6867 +3 6552 5695 6617 +3 5589 5948 6318 +3 5684 6539 6738 +3 5922 6011 6546 +3 5371 5946 6935 +3 5370 5943 6765 +3 5595 5940 6729 +3 5808 5936 6717 +3 5936 266 6717 +3 5706 6062 6749 +3 5365 5964 6890 +3 5562 5931 6396 +3 6055 5682 6622 +3 442 6138 6728 +3 5593 6244 6835 +3 387 386 6131 +3 6144 5538 6865 +3 5572 6103 6193 +3 5960 6386 6869 +3 5426 6143 6256 +3 6143 5649 6256 +3 5940 5480 6373 +3 443 442 6728 +3 5703 6081 6321 +3 5797 5927 6786 +3 5731 6342 6426 +3 6758 5713 6856 +3 5816 6162 6898 +3 5423 5962 6412 +3 6129 5737 6883 +3 5605 6201 6304 +3 5685 6167 6494 +3 453 452 6149 +3 5600 5959 6372 +3 6014 348 6271 +3 5528 6165 6677 +3 5492 5943 6355 +3 5973 5684 6738 +3 6154 5444 6879 +3 327 328 6207 +3 6286 5600 6543 +3 5976 5610 6272 +3 6540 5886 6809 +3 6195 5609 6251 +3 5556 5928 6476 +3 5971 5424 6691 +3 5503 5958 6885 +3 6535 5573 6740 +3 6268 5966 6443 +3 414 5932 6613 +3 6181 5462 6610 +3 6023 5358 6225 +3 5768 6023 6225 +3 6201 5605 6344 +3 5970 5499 6696 +3 5384 5970 6470 +3 6035 5683 6277 +3 6172 5575 6339 +3 5806 6465 6662 +3 5370 6007 6240 +3 5788 6325 6631 +3 6044 6459 6899 +3 5930 5691 6513 +3 383 382 6135 +3 5646 6045 6418 +3 5501 6023 6936 +3 6058 5427 6359 +3 6057 5554 6196 +3 5484 5937 6644 +3 5635 5932 6572 +3 5932 5635 6713 +3 6038 5611 6442 +3 6000 5727 6331 +3 6001 5776 6353 +3 5494 6734 6740 +3 5692 6010 6241 +3 5954 5361 6351 +3 5596 6024 6254 +3 6024 5433 6254 +3 5995 5892 6779 +3 5716 5934 6783 +3 5578 5946 6392 +3 5997 5376 6253 +3 6060 5573 6755 +3 6023 5768 6936 +3 6033 368 6419 +3 6240 5623 6355 +3 5622 6153 6487 +3 6214 5673 6591 +3 5815 6214 6591 +3 6430 5747 6785 +3 6008 5565 6308 +3 5859 6790 6825 +3 6121 5637 6255 +3 5378 6121 6255 +3 5549 6134 6146 +3 5940 6372 6729 +3 6372 5410 6729 +3 5570 5955 6366 +3 5948 5758 6873 +3 5897 6238 6408 +3 5981 5559 6294 +3 5643 5938 6725 +3 5944 5662 6690 +3 5963 5514 6904 +3 5980 5384 6470 +3 5758 5948 6593 +3 5948 418 6593 +3 5564 6043 6216 +3 5967 5498 6576 +3 6014 5642 6436 +3 347 6014 6436 +3 6221 5653 6340 +3 5655 6413 6508 +3 6245 5442 6377 +3 5649 6127 6269 +3 5925 6303 6831 +3 6303 5404 6831 +3 5483 5941 6522 +3 5463 6337 6379 +3 6337 5763 6379 +3 5724 6072 6739 +3 5956 5858 6766 +3 6234 345 6800 +3 5657 6004 6506 +3 6004 257 6506 +3 359 360 6166 +3 5999 5597 6338 +3 6124 5515 6713 +3 280 281 6566 +3 5580 6139 6427 +3 6015 5391 6552 +3 6527 5910 6932 +3 5478 6556 6748 +3 6533 5440 6801 +3 6090 6632 6646 +3 6214 5670 6795 +3 5522 6111 6861 +3 5577 5943 6507 +3 5960 5537 6386 +3 5946 5578 6637 +3 5440 6324 6801 +3 428 427 6603 +3 5989 5500 6335 +3 5603 5989 6335 +3 5385 6049 6309 +3 5455 6430 6480 +3 5947 5541 6652 +3 5677 6075 6558 +3 5440 6125 6324 +3 6125 5654 6324 +3 5951 334 6457 +3 6104 5560 6179 +3 5524 6026 6660 +3 348 349 6271 +3 5488 5945 6884 +3 6043 5749 6808 +3 5372 6043 6808 +3 6555 5417 6743 +3 5949 5481 6872 +3 5567 5953 6460 +3 6405 5652 6840 +3 256 6004 6569 +3 6391 5749 6813 +3 5380 6264 6820 +3 453 6149 6285 +3 344 345 6234 +3 5490 6381 6833 +3 6107 6496 6909 +3 5950 5465 6620 +3 5629 6176 6484 +3 5657 5952 6672 +3 5690 5949 6603 +3 5379 6293 6475 +3 5627 6068 6322 +3 6068 5395 6322 +3 6240 6007 6677 +3 5558 6064 6314 +3 329 330 6162 +3 431 430 6163 +3 6090 5534 6632 +3 5726 5979 6895 +3 5979 5505 6895 +3 5564 6226 6933 +3 5682 6055 6947 +3 5610 6273 6298 +3 6162 5569 6898 +3 255 256 6569 +3 5706 5972 6811 +3 6242 5760 6858 +3 5592 6225 6754 +3 5662 5968 6690 +3 5387 6019 6380 +3 6019 5615 6380 +3 6180 5428 6346 +3 5391 6015 6435 +3 6015 5638 6435 +3 5716 6157 6582 +3 5395 6068 6875 +3 5955 5711 6514 +3 6226 5896 6933 +3 6058 6598 6816 +3 6487 6153 6935 +3 6147 255 6569 +3 5908 6028 6900 +3 5962 5423 6595 +3 5514 6871 6904 +3 5514 6315 6871 +3 6158 5671 6547 +3 5798 6142 6919 +3 5585 6026 6650 +3 5415 6031 6417 +3 6517 5951 6712 +3 6010 5692 6707 +3 5362 6010 6707 +3 5884 6288 6946 +3 5534 6071 6888 +3 6015 5508 6320 +3 5638 6015 6320 +3 6319 5629 6561 +3 5608 6003 6310 +3 5551 5957 6551 +3 5652 6341 6840 +3 5709 6057 6780 +3 5565 6156 6511 +3 6156 5708 6511 +3 5519 6005 6521 +3 5975 5621 6387 +3 5563 6113 6270 +3 5987 5503 6344 +3 6624 5476 6846 +3 5968 5391 6690 +3 6672 5952 6891 +3 6079 5742 6847 +3 6118 5576 6245 +3 5569 6120 6303 +3 6149 5640 6285 +3 6209 5927 6504 +3 5661 6008 6308 +3 6175 5794 6750 +3 5402 6175 6750 +3 283 6055 6622 +3 6289 449 6674 +3 5992 5802 6942 +3 5597 5999 6566 +3 413 412 6572 +3 5832 5966 6647 +3 5477 5983 6371 +3 5502 6672 6891 +3 5664 6449 6886 +3 5684 5973 6451 +3 5514 6009 6315 +3 5970 5586 6470 +3 5860 6058 6359 +3 5681 6191 6300 +3 6191 5527 6300 +3 6026 5367 6650 +3 409 6130 6948 +3 5793 6063 6719 +3 6052 5699 6756 +3 6476 5403 6855 +3 6126 5573 6535 +3 5699 6126 6535 +3 5968 5695 6552 +3 6410 5838 6510 +3 5381 6410 6510 +3 6005 5644 6521 +3 6188 5456 6584 +3 5442 5978 6434 +3 262 6150 6908 +3 6588 5444 6943 +3 5809 6234 6800 +3 5777 6205 6689 +3 6033 6419 6632 +3 6201 6344 6885 +3 5586 5970 6696 +3 6152 5669 6567 +3 5596 6254 6662 +3 6254 5806 6662 +3 5401 5969 6614 +3 6107 5805 6496 +3 6616 5702 6794 +3 6032 5544 6298 +3 280 5999 6625 +3 6116 5621 6301 +3 5728 6116 6301 +3 5634 6256 6269 +3 6146 5759 6789 +3 5424 5971 6587 +3 5653 6343 6619 +3 6343 5853 6619 +3 6547 5492 6880 +3 5977 5861 6746 +3 5481 6287 6722 +3 6287 5855 6722 +3 5510 5995 6378 +3 5722 5991 6902 +3 5991 5539 6902 +3 5944 6083 6533 +3 6294 5559 6845 +3 5591 6148 6466 +3 5724 6196 6923 +3 5678 6441 6560 +3 6072 445 6739 +3 5678 5988 6668 +3 5988 376 6668 +3 6385 5383 6903 +3 6109 5843 6397 +3 5384 5980 6484 +3 450 449 6289 +3 380 379 6222 +3 5444 6398 6943 +3 5663 6101 6239 +3 6173 5608 6279 +3 5717 6173 6279 +3 6594 5775 6667 +3 5663 6239 6282 +3 6130 5814 6948 +3 5985 5418 6445 +3 398 6078 6642 +3 5428 5996 6915 +3 6086 5571 6243 +3 334 335 6457 +3 6584 5456 6886 +3 6284 5739 6424 +3 5640 6284 6424 +3 420 419 6212 +3 6121 5378 6909 +3 363 6113 6676 +3 5723 6091 6701 +3 6091 5445 6701 +3 5980 5497 6561 +3 6004 5601 6569 +3 5982 5685 6772 +3 6139 5719 6427 +3 6101 5423 6239 +3 6234 5809 6440 +3 5633 6234 6440 +3 6239 5636 6282 +3 6062 5613 6445 +3 5391 6499 6690 +3 6499 5944 6690 +3 6243 5833 6610 +3 6519 5733 6597 +3 331 332 6295 +3 433 432 6296 +3 5979 5362 6707 +3 386 385 6368 +3 5819 6375 6829 +3 5617 6070 6390 +3 5749 6043 6374 +3 5680 6018 6784 +3 5558 6450 6828 +3 6019 5510 6378 +3 5615 6019 6378 +3 6142 5369 6919 +3 407 406 6830 +3 6232 5783 6692 +3 5454 6232 6692 +3 385 384 6643 +3 6003 5608 6503 +3 5422 6037 6423 +3 6037 5630 6423 +3 6430 5756 6480 +3 5597 6070 6338 +3 6288 5421 6946 +3 5581 6122 6480 +3 6238 5613 6408 +3 5579 6096 6665 +3 6415 5882 6856 +3 391 390 6227 +3 5587 6088 6330 +3 5698 6189 6334 +3 6021 5595 6729 +3 6077 5436 6279 +3 5608 6077 6279 +3 339 340 6387 +3 6188 5591 6466 +3 5412 6110 6251 +3 6009 5359 6682 +3 366 367 6420 +3 5669 6455 6567 +3 5565 6099 6308 +3 6407 5774 6743 +3 6132 5617 6233 +3 5707 6515 6605 +3 5690 6095 6287 +3 415 414 6613 +3 5539 6317 6902 +3 362 363 6676 +3 6112 5581 6680 +3 5598 6131 6368 +3 6029 5421 6349 +3 5606 6029 6349 +3 5375 6169 6343 +3 5672 6000 6716 +3 6000 5430 6716 +3 6150 5796 6908 +3 5767 5985 6914 +3 406 6173 6830 +3 5696 6066 6742 +3 6333 5994 6793 +3 6091 5723 6257 +3 5378 5987 6626 +3 429 428 6468 +3 5435 6187 6233 +3 5985 5507 6582 +3 6027 5579 6359 +3 6072 5724 6923 +3 5603 6056 6306 +3 6194 5797 6786 +3 5561 6194 6786 +3 5675 6113 6528 +3 6113 5563 6528 +3 6109 5373 6399 +3 6117 5674 6434 +3 6189 5582 6812 +3 6147 5601 6857 +3 5991 5406 6770 +3 451 450 6238 +3 5988 5678 6578 +3 5386 6054 6662 +3 5989 5441 6817 +3 5727 6000 6846 +3 6578 5464 6596 +3 5601 6174 6483 +3 284 285 6524 +3 5618 6006 6512 +3 5994 5509 6793 +3 6845 6121 6909 +3 5767 6289 6674 +3 6166 360 6866 +3 6324 5654 6530 +3 5771 6324 6530 +3 5794 6175 6620 +3 5966 6093 6647 +3 5422 6292 6752 +3 6348 5619 6760 +3 5830 6385 6903 +3 6374 5896 6742 +3 5457 6374 6742 +3 5701 6564 6918 +3 5450 6146 6789 +3 5494 5992 6734 +3 5993 5424 6587 +3 5665 5997 6534 +3 5482 6341 6944 +3 5422 6080 6292 +3 6129 5543 6815 +3 405 6003 6503 +3 437 436 6244 +3 6057 6196 6780 +3 6723 6212 6929 +3 6496 5735 6909 +3 5408 6184 6467 +3 6184 5685 6467 +3 6064 5602 6314 +3 6022 5363 6883 +3 352 353 6583 +3 6381 5842 6833 +3 6241 5439 6425 +3 5993 5520 6592 +3 6358 5856 6669 +3 5366 6358 6669 +3 6177 5648 6553 +3 6223 5458 6534 +3 408 407 6362 +3 6129 5363 6491 +3 5672 6129 6491 +3 281 6098 6566 +3 397 396 6623 +3 6125 5440 6321 +3 5633 6125 6321 +3 447 446 6657 +3 6112 5430 6261 +3 6340 5653 6619 +3 6061 5385 6606 +3 5625 6350 6562 +3 406 405 6503 +3 6259 443 6728 +3 5535 6022 6429 +3 6206 5846 6764 +3 6213 5624 6453 +3 6054 5386 6339 +3 5641 6231 6258 +3 6310 5450 6452 +3 5790 6166 6866 +3 5601 6197 6857 +3 6484 6176 6804 +3 5641 6275 6369 +3 5366 6092 6358 +3 6092 5634 6358 +3 5996 5671 6915 +3 6087 5446 6384 +3 5638 6087 6384 +3 6398 5676 6538 +3 5811 6398 6538 +3 6133 5549 6881 +3 6135 382 6926 +3 5421 6001 6946 +3 6017 5714 6879 +3 6160 5412 6251 +3 383 6135 6826 +3 6399 5641 6759 +3 5455 6122 6495 +3 6116 5728 6724 +3 338 6116 6724 +3 6237 5859 6825 +3 358 359 6461 +3 330 331 6601 +3 432 431 6600 +3 5753 6136 6767 +3 6136 5577 6767 +3 5999 5730 6625 +3 6095 5599 6894 +3 6380 5763 6447 +3 5387 6380 6447 +3 6046 5977 6746 +3 400 6053 6395 +3 5393 6257 6932 +3 6031 5659 6417 +3 5887 6061 6606 +3 390 389 6573 +3 6008 370 6827 +3 6305 5744 6681 +3 6056 5603 6682 +3 5756 6430 6913 +3 5543 6002 6710 +3 5369 6052 6756 +3 367 6033 6420 +3 5613 6238 6289 +3 6051 5616 6404 +3 5525 6051 6404 +3 5626 6352 6433 +3 6352 5754 6433 +3 6191 5813 6763 +3 5527 6191 6763 +3 6370 5631 6736 +3 6076 5655 6508 +3 5377 6307 6571 +3 6011 5789 6546 +3 6127 5478 6269 +3 6163 430 6532 +3 6108 5379 6475 +3 5656 6108 6475 +3 412 6389 6572 +3 6011 5550 6806 +3 5360 6076 6508 +3 5492 6355 6880 +3 6215 5581 6480 +3 6081 5633 6321 +3 6137 5740 6848 +3 6173 406 6503 +3 6140 5901 6734 +3 5394 6063 6562 +3 6325 5788 6580 +3 5467 6325 6580 +3 5604 6199 6752 +3 5692 6241 6425 +3 6070 5445 6338 +3 5609 6160 6251 +3 5523 6049 6778 +3 6049 5706 6778 +3 6355 6741 6880 +3 6261 5430 6331 +3 5602 6110 6683 +3 6042 5532 6413 +3 6211 5624 6505 +3 5611 6038 6497 +3 5530 6068 6414 +3 6068 5627 6414 +3 5760 6770 6858 +3 5646 6085 6446 +3 6085 5533 6446 +3 5665 6273 6274 +3 6273 5610 6274 +3 6009 5876 6709 +3 5584 6171 6656 +3 6171 5731 6656 +3 5790 6203 6554 +3 274 275 6715 +3 6154 5714 6523 +3 5526 6046 6746 +3 5710 6188 6466 +3 436 435 6835 +3 6024 5565 6511 +3 365 366 6383 +3 5787 6219 6460 +3 6219 5567 6460 +3 6053 5632 6395 +3 6275 5680 6369 +3 6019 5387 6553 +3 6122 5455 6480 +3 343 6081 6673 +3 454 453 6285 +3 6098 5597 6566 +3 423 422 6478 +3 6033 5534 6888 +3 5659 6031 6640 +3 6031 5512 6640 +3 6642 6078 6848 +3 5605 6107 6626 +3 6409 5693 6655 +3 6222 5668 6375 +3 380 6222 6375 +3 6456 5701 6918 +3 351 6079 6847 +3 285 6 6493 +3 6375 5819 6926 +3 6745 5852 6843 +3 6253 5376 6530 +3 6117 5377 6571 +3 5674 6117 6571 +3 5910 6527 6685 +3 6527 5536 6685 +3 6236 5473 6859 +3 5881 6183 6570 +3 6329 5372 6808 +3 5886 6329 6808 +3 5592 6027 6906 +3 5682 6098 6622 +3 6098 282 6622 +3 6169 5375 6615 +3 278 279 6402 +3 6106 5587 6330 +3 6062 5479 6408 +3 5613 6062 6408 +3 6066 5457 6742 +3 6034 5360 6508 +3 6790 5750 6825 +3 6197 5708 6730 +3 5389 6040 6504 +3 6040 5636 6504 +3 6116 339 6387 +3 6018 6337 6784 +3 6385 5947 6911 +3 5750 6385 6911 +3 6449 5796 6886 +3 6086 5402 6750 +3 6038 5389 6497 +3 5562 6396 6810 +3 5748 6278 6499 +3 5855 6516 6865 +3 5358 6023 6781 +3 6023 5683 6781 +3 6170 5782 6405 +3 5389 6038 6639 +3 6038 5659 6639 +3 5653 6376 6444 +3 6025 5657 6672 +3 5502 6025 6672 +3 6081 343 6788 +3 5633 6081 6788 +3 5615 6378 6471 +3 5783 6232 6366 +3 6232 5570 6366 +3 6048 5652 6648 +3 6246 5645 6255 +3 5447 6179 6513 +3 5599 6204 6356 +3 6104 5713 6735 +3 5359 6104 6735 +3 6026 5585 6660 +3 5758 6219 6873 +3 5640 6149 6565 +3 6370 5764 6629 +3 5512 6031 6604 +3 6061 5865 6479 +3 5385 6061 6479 +3 5648 6177 6691 +3 6037 6199 6773 +3 6394 5709 6663 +3 6715 5781 6787 +3 5457 6066 6427 +3 5530 6039 6550 +3 5418 6028 6749 +3 6028 5523 6778 +3 5588 6235 6884 +3 5671 6265 6661 +3 6311 5411 6928 +3 5899 6311 6928 +3 420 6212 6723 +3 6375 5668 6829 +3 6123 5673 6570 +3 5540 6123 6570 +3 5539 6087 6448 +3 6087 5638 6448 +3 5534 6033 6632 +3 5827 6399 6759 +3 6384 5748 6435 +3 5638 6384 6435 +3 6133 5721 6732 +3 403 6133 6732 +3 422 6059 6478 +3 5363 6129 6883 +3 5373 6109 6397 +3 6090 5651 6498 +3 5534 6090 6498 +3 5670 6032 6795 +3 6233 5617 6390 +3 5443 6036 6705 +3 6030 5359 6735 +3 6046 5526 6876 +3 273 274 6332 +3 6419 5661 6632 +3 5646 6418 6490 +3 6418 5770 6490 +3 5493 6260 6487 +3 6231 5631 6258 +3 6032 5438 6795 +3 6089 264 6469 +3 6043 5564 6933 +3 6050 5575 6575 +3 6070 5617 6549 +3 6080 5422 6423 +3 5560 6104 6709 +3 371 372 6730 +3 5621 6116 6387 +3 6531 5745 6754 +3 6053 5740 6520 +3 6045 5646 6594 +3 6609 5857 6782 +3 5637 6246 6255 +3 5747 6172 6339 +3 5708 6483 6511 +3 5731 6364 6656 +3 6034 5874 6718 +3 5479 6062 6811 +3 6062 5706 6811 +3 5612 6227 6573 +3 6131 386 6368 +3 6155 5743 6764 +3 5484 6155 6764 +3 342 343 6673 +3 5727 6263 6264 +3 6263 5594 6264 +3 6085 5646 6490 +3 5448 6085 6490 +3 6190 5818 6528 +3 6055 284 6524 +3 5703 6321 6921 +3 6035 5358 6781 +3 5683 6035 6781 +3 6136 5753 6550 +3 5643 6077 6452 +3 5413 6164 6334 +3 6556 5752 6803 +3 5974 6556 6803 +3 5427 6058 6816 +3 5637 6297 6548 +3 5461 6044 6899 +3 6184 5408 6698 +3 5726 6184 6698 +3 5382 6635 6649 +3 6040 5389 6639 +3 5512 6040 6640 +3 5761 6388 6839 +3 6130 408 6362 +3 5518 6037 6773 +3 5555 6035 6819 +3 6156 371 6730 +3 5797 6194 6313 +3 6194 5436 6313 +3 6132 5373 6397 +3 5779 6182 6592 +3 5784 6236 6859 +3 6290 5588 6884 +3 401 400 6395 +3 6041 5452 6853 +3 6462 5668 6940 +3 5869 6266 6944 +3 6065 434 6559 +3 6042 5681 6776 +3 5397 6042 6776 +3 6105 278 6402 +3 279 280 6625 +3 5473 6236 6731 +3 5628 6186 6319 +3 6164 5622 6334 +3 6048 5869 6944 +3 6067 5679 6721 +3 5480 6067 6721 +3 5668 6576 6940 +3 6209 5636 6412 +3 5700 6517 6712 +3 5541 6137 6848 +3 6123 5396 6591 +3 5673 6123 6591 +3 6357 5607 6787 +3 6071 5534 6498 +3 6131 5712 6727 +3 387 6131 6727 +3 5631 6231 6361 +3 5905 6661 6875 +3 5906 6299 6762 +3 6238 450 6289 +3 6400 5734 6824 +3 5898 6400 6824 +3 5648 6364 6426 +3 6364 5731 6426 +3 6094 5430 6814 +3 6333 5780 6635 +3 5705 6333 6635 +3 6189 5413 6334 +3 6714 5741 6747 +3 6137 5830 6525 +3 5452 6219 6853 +3 6219 5787 6853 +3 6266 5482 6944 +3 6247 5435 6390 +3 266 267 6717 +3 5584 6182 6907 +3 6182 5779 6907 +3 5631 6370 6629 +3 6170 5557 6931 +3 5782 6170 6931 +3 271 6048 6648 +3 381 380 6375 +3 343 344 6788 +3 5444 6588 6879 +3 6588 6017 6879 +3 5650 6089 6469 +3 5731 6171 6342 +3 5462 6243 6610 +3 6363 5920 6489 +3 5617 6132 6397 +3 6122 5619 6495 +3 5768 6906 6937 +3 6084 5425 6708 +3 6194 6849 6938 +3 6221 5625 6415 +3 5701 6065 6559 +3 5430 6112 6814 +3 5601 6147 6569 +3 6082 5546 6502 +3 5561 6130 6849 +3 5445 6070 6549 +3 5653 6221 6376 +3 6221 5447 6376 +3 6054 5596 6662 +3 5850 6416 6702 +3 6416 5697 6702 +3 6735 5713 6758 +3 6275 5641 6399 +3 424 423 6486 +3 5733 6361 6597 +3 6711 5918 6771 +3 6051 5525 6719 +3 6194 5561 6849 +3 264 265 6469 +3 6239 5423 6412 +3 5800 6100 6482 +3 6128 6034 6718 +3 5359 6056 6682 +3 5796 6150 6584 +3 6150 5591 6584 +3 6083 5440 6533 +3 5757 6706 6896 +3 6181 5922 6714 +3 6077 5643 6725 +3 6055 5566 6947 +3 5712 6131 6753 +3 6131 5598 6753 +3 5896 6536 6742 +3 5439 6258 6629 +3 368 369 6419 +3 5604 6216 6354 +3 5375 6336 6615 +3 5951 6653 6712 +3 6653 5488 6712 +3 5720 6609 6782 +3 5637 6121 6501 +3 6231 5641 6369 +3 6222 5967 6576 +3 6632 5661 6646 +3 5430 6094 6716 +3 6093 5537 6647 +3 5715 6144 6865 +3 5732 6723 6929 +3 6311 5899 6753 +3 325 326 6428 +3 6710 5836 6815 +3 6259 5679 6458 +3 5724 6259 6458 +3 6060 5494 6740 +3 5625 6221 6340 +3 346 347 6436 +3 5639 6587 6802 +3 6587 5971 6802 +3 6536 5696 6742 +3 6617 5695 6743 +3 5675 6203 6676 +3 268 269 6526 +3 5587 6106 6838 +3 6079 352 6583 +3 5424 6364 6691 +3 5423 6124 6595 +3 5741 6463 6747 +3 5412 6160 6704 +3 5425 6119 6708 +3 6302 5620 6489 +3 6165 5412 6704 +3 5634 6269 6695 +3 5374 6102 6523 +3 6127 5649 6877 +3 5701 6296 6564 +3 6296 5766 6564 +3 6295 5700 6563 +3 5765 6295 6563 +3 6168 5664 6891 +3 6210 5710 6837 +3 6314 5602 6683 +3 6211 5382 6649 +3 6301 5621 6638 +3 5683 6519 6597 +3 6350 5836 6710 +3 270 271 6648 +3 446 6072 6657 +3 5487 6246 6548 +3 5400 6100 6930 +3 5608 6173 6503 +3 5432 6170 6405 +3 6376 5691 6444 +3 6078 397 6623 +3 376 375 6668 +3 6262 5743 6641 +3 5381 6262 6641 +3 6284 5640 6565 +3 6326 5670 6608 +3 5628 6178 6675 +3 6163 6532 6733 +3 6442 5791 6581 +3 5470 6442 6581 +3 6236 5738 6731 +3 5630 6141 6510 +3 5613 6289 6914 +3 6440 5465 6529 +3 5499 6711 6771 +3 6121 5559 6501 +3 6186 5628 6675 +3 5873 6297 6501 +3 6457 335 6878 +3 5778 6383 6633 +3 6383 5746 6633 +3 370 371 6827 +3 6184 5726 6895 +3 6148 5420 6466 +3 6161 268 6526 +3 6219 5452 6873 +3 5554 6072 6923 +3 6574 5658 6678 +3 6391 5719 6494 +3 6288 5864 6349 +3 5721 6133 6881 +3 6427 5719 6813 +3 6177 6553 6920 +3 6372 5940 6373 +3 5600 6372 6373 +3 441 440 6543 +3 5526 6114 6876 +3 5578 6084 6645 +3 6081 5703 6673 +3 6094 5543 6590 +3 6535 5901 6756 +3 5699 6535 6756 +3 6231 5437 6361 +3 5616 6112 6680 +3 6149 5897 6565 +3 5619 6261 6331 +3 6256 5634 6892 +3 5743 6262 6665 +3 6262 5579 6665 +3 5411 6075 6928 +3 6083 5522 6861 +3 5654 6125 6529 +3 5436 6077 6725 +3 5547 6105 6822 +3 6210 5857 6609 +3 5824 6074 6757 +3 359 6166 6461 +3 5594 6074 6761 +3 6083 6861 6921 +3 5437 6231 6369 +3 6234 5633 6788 +3 371 6156 6827 +3 434 433 6559 +3 395 394 6703 +3 5451 6137 6525 +3 6179 5447 6856 +3 6661 5395 6875 +3 5385 6309 6606 +3 5635 6124 6713 +3 6822 5730 6841 +3 6402 279 6625 +3 5429 6090 6646 +3 6343 5653 6444 +3 257 258 6506 +3 6320 5820 6448 +3 5627 6084 6708 +3 416 415 6542 +3 381 6375 6926 +3 6624 5823 6807 +3 6078 5541 6848 +3 332 333 6517 +3 6459 5705 6889 +3 6358 5634 6695 +3 6088 5725 6693 +3 448 6097 6674 +3 6861 5703 6921 +3 6153 5622 6796 +3 6344 5605 6626 +3 6267 5778 6633 +3 5460 6267 6633 +3 6433 5754 6509 +3 5383 6433 6509 +3 6151 416 6542 +3 5684 6451 6684 +3 430 429 6532 +3 6214 5438 6545 +3 5673 6214 6545 +3 6686 5442 6774 +3 6085 5448 6925 +3 6577 5660 6598 +3 6107 5378 6626 +3 5517 6312 6352 +3 6312 5754 6352 +3 5402 6086 6945 +3 6086 5725 6945 +3 6327 5594 6761 +3 6097 5767 6674 +3 6266 5607 6357 +3 5929 6266 6357 +3 6157 5716 6783 +3 5585 6157 6783 +3 5440 6083 6921 +3 6129 5672 6590 +3 5543 6129 6590 +3 5435 6233 6390 +3 6211 6505 6731 +3 5952 6168 6891 +3 5449 6416 6780 +3 6174 5433 6483 +3 5666 6092 6869 +3 5688 6103 6768 +3 6103 5572 6768 +3 5622 6164 6796 +3 6250 5889 6586 +3 5447 6221 6415 +3 6088 5402 6945 +3 5725 6088 6945 +3 5486 6391 6494 +3 6425 5439 6629 +3 6165 5623 6677 +3 5844 6574 6678 +3 6379 5763 6380 +3 5615 6379 6380 +3 5421 6288 6349 +3 373 374 6857 +3 346 6436 6800 +3 5603 6315 6682 +3 5714 6154 6879 +3 5852 6323 6843 +3 5700 6295 6517 +3 6295 332 6517 +3 5828 6577 6598 +3 6124 5635 6595 +3 5487 6745 6843 +3 5391 6435 6499 +3 6435 5748 6499 +3 5647 6202 6473 +3 5687 6208 6621 +3 6208 5374 6621 +3 6110 5412 6683 +3 374 6147 6857 +3 5593 6268 6443 +3 6113 5675 6676 +3 5445 6091 6841 +3 5451 6347 6520 +3 6302 5393 6726 +3 5768 6225 6906 +3 6225 5592 6906 +3 6298 5544 6658 +3 6726 5393 6832 +3 5636 6239 6412 +3 6360 5689 6488 +3 5714 6360 6488 +3 388 387 6727 +3 6092 5366 6869 +3 5799 6185 6887 +3 6185 276 6887 +3 5568 6218 6897 +3 6095 5416 6851 +3 5416 6095 6894 +3 5751 6152 6567 +3 5572 6242 6858 +3 6103 5688 6878 +3 418 417 6593 +3 6337 5590 6688 +3 5763 6337 6688 +3 6281 5818 6614 +3 6491 5363 6670 +3 5823 6491 6670 +3 5728 6193 6724 +3 6193 337 6724 +3 5872 6314 6683 +3 6272 5610 6658 +3 6425 5764 6579 +3 5692 6425 6579 +3 354 355 6720 +3 6202 5647 6941 +3 6318 5948 6873 +3 6338 5445 6841 +3 6635 5780 6649 +3 5756 6215 6480 +3 5645 6246 6843 +3 5851 6539 6684 +3 6539 5684 6684 +3 5844 6459 6889 +3 5563 6190 6528 +3 282 283 6622 +3 5455 6495 6874 +3 6598 5660 6816 +3 5378 6107 6909 +3 5530 6414 6531 +3 6414 5745 6531 +3 5894 6169 6615 +3 5610 6298 6658 +3 378 377 6634 +3 6217 5380 6607 +3 6112 5616 6814 +3 5373 6275 6399 +3 6111 5703 6861 +3 5636 6209 6504 +3 6612 5398 6860 +3 5957 6612 6860 +3 399 398 6642 +3 449 448 6674 +3 6199 5828 6773 +3 6479 5865 6777 +3 5739 6479 6777 +3 6367 5831 6844 +3 5471 6367 6844 +3 5669 6152 6703 +3 6114 5644 6876 +3 6315 6009 6682 +3 5544 6128 6718 +3 5780 6333 6793 +3 5685 6184 6772 +3 6183 5540 6570 +3 6162 330 6601 +3 431 6163 6600 +3 6263 5476 6757 +3 5796 6584 6886 +3 6203 5790 6866 +3 361 6203 6866 +3 5896 6226 6536 +3 5814 6224 6948 +3 6224 410 6948 +3 6218 5427 6816 +3 6296 5701 6559 +3 433 6296 6559 +3 5679 6138 6721 +3 6203 5675 6554 +3 5649 6248 6877 +3 6258 5439 6759 +3 5743 6155 6641 +3 350 351 6847 +3 6138 5679 6728 +3 6393 5803 6744 +3 5466 6393 6744 +3 5888 6138 6818 +3 6138 442 6818 +3 5559 6121 6845 +3 6525 5830 6903 +3 5403 6792 6877 +3 6423 5630 6502 +3 5453 6120 6893 +3 6035 6277 6819 +3 5591 6188 6584 +3 421 420 6723 +3 5851 6283 6539 +3 6283 5557 6539 +3 6500 5794 6620 +3 5465 6500 6620 +3 337 338 6724 +3 364 365 6821 +3 404 403 6732 +3 5623 6240 6677 +3 5577 6136 6779 +3 6202 5461 6678 +3 6152 395 6703 +3 445 444 6739 +3 6289 5767 6914 +3 6226 5400 6536 +3 5833 6599 6610 +3 6599 5742 6610 +3 6586 5680 6784 +3 6130 6362 6849 +3 5368 6215 6912 +3 6215 5756 6912 +3 5441 6306 6474 +3 5867 6486 6805 +3 6486 5769 6805 +3 6651 5694 6844 +3 5669 6291 6455 +3 6291 5786 6455 +3 356 357 6834 +3 6196 5554 6923 +3 6323 5645 6843 +3 6252 5658 6574 +3 5428 6180 6636 +3 5730 6402 6625 +3 6410 5618 6411 +3 5838 6410 6411 +3 5671 6158 6915 +3 6297 5637 6501 +3 345 346 6800 +3 6260 5622 6487 +3 5641 6258 6759 +3 5543 6710 6815 +3 5619 6348 6495 +3 442 441 6818 +3 5623 6165 6704 +3 384 383 6826 +3 6182 5584 6656 +3 5759 6612 6868 +3 5755 6217 6575 +3 5708 6156 6730 +3 5821 6417 6544 +3 261 262 6908 +3 6538 5676 6737 +3 5369 6140 6919 +3 5668 6222 6576 +3 6429 6022 6883 +3 360 361 6866 +3 5638 6320 6448 +3 6388 5474 6839 +3 276 277 6887 +3 5788 6686 6774 +3 6431 5664 6886 +3 5664 6432 6891 +3 5450 6310 6882 +3 6455 5459 6567 +3 5740 6642 6848 +3 6227 390 6573 +3 440 6286 6543 +3 382 381 6926 +3 5420 6186 6675 +3 410 409 6948 +3 6491 5823 6624 +3 5456 6210 6609 +3 6362 407 6830 +3 6543 5888 6818 +3 441 6543 6818 +3 5570 6163 6733 +3 6422 5704 6602 +3 6330 6088 6693 +3 5590 6187 6688 +3 6276 5587 6838 +3 6235 5488 6884 +3 5549 6146 6881 +3 6146 5450 6882 +3 5623 6704 6741 +3 5651 6217 6607 +3 5661 6308 6646 +3 6246 5637 6548 +3 5375 6343 6444 +3 5462 6181 6714 +3 6170 5432 6738 +3 6439 5871 6859 +3 5473 6439 6859 +3 5372 6329 6577 +3 5964 6659 6890 +3 6659 5722 6890 +3 6206 5743 6665 +3 5658 6202 6678 +3 6459 5844 6899 +3 5474 6388 6797 +3 6388 5804 6797 +3 5704 6422 6472 +3 6422 5694 6472 +3 5704 6509 6602 +3 6849 5717 6938 +3 5707 6205 6720 +3 6421 5867 6805 +3 5472 6421 6805 +3 6431 5720 6432 +3 5664 6431 6432 +3 5624 6211 6649 +3 6153 5371 6935 +3 6205 5707 6689 +3 6291 5669 6834 +3 5702 6187 6794 +3 6187 5435 6794 +3 6157 5585 6900 +3 6259 5724 6739 +3 444 6259 6739 +3 5718 6158 6880 +3 5795 6541 6697 +3 5839 6347 6850 +3 6382 270 6648 +3 6354 5372 6577 +3 6477 5813 6537 +3 5438 6273 6687 +3 5668 6462 6829 +3 5476 6624 6807 +3 6158 5428 6915 +3 5557 6161 6931 +3 6218 5660 6897 +3 5566 6381 6616 +3 6381 5863 6616 +3 5382 6252 6574 +3 5747 6339 6769 +3 6173 5717 6830 +3 6176 5851 6804 +3 6205 354 6720 +3 5738 6236 6862 +3 6236 5553 6862 +3 6322 5835 6645 +3 6481 5466 6618 +3 5879 6481 6618 +3 5572 6192 6768 +3 5497 6319 6561 +3 5727 6264 6760 +3 6264 5380 6760 +3 6172 5455 6874 +3 5710 6178 6837 +3 6199 5422 6752 +3 5463 6250 6586 +3 6637 5578 6645 +3 5835 6637 6645 +3 5566 6198 6947 +3 6196 5449 6780 +3 5375 6444 6798 +3 5589 6292 6929 +3 6541 5475 6697 +3 5905 6547 6661 +3 5437 6277 6597 +3 6277 5683 6597 +3 5652 6382 6648 +3 5856 6695 6748 +3 5479 6284 6565 +3 5446 6301 6638 +3 6348 5755 6495 +3 5743 6206 6764 +3 5435 6198 6794 +3 5438 6214 6795 +3 5863 6177 6920 +3 375 6441 6668 +3 5620 6363 6489 +3 6280 5583 6825 +3 5750 6280 6825 +3 5738 6211 6731 +3 5719 6467 6494 +3 6420 6033 6888 +3 5704 6525 6903 +3 6192 5572 6858 +3 6617 5931 6917 +3 5508 6617 6917 +3 5620 6302 6726 +3 6197 373 6857 +3 6249 5924 6771 +3 5436 6194 6938 +3 6447 5763 6688 +3 5691 6376 6513 +3 6376 5447 6513 +3 5679 6259 6728 +3 6450 5736 6828 +3 5780 6453 6649 +3 6453 5624 6649 +3 6299 388 6727 +3 5448 6490 6679 +3 6490 5770 6679 +3 6383 5778 6821 +3 365 6383 6821 +3 6477 5474 6797 +3 5813 6477 6797 +3 5442 6434 6774 +3 5388 6557 6671 +3 6557 5795 6671 +3 6329 5660 6577 +3 6339 5386 6769 +3 6258 5631 6629 +3 5958 6201 6885 +3 394 6401 6703 +3 5416 6516 6851 +3 6516 5855 6851 +3 6492 5899 6928 +3 6772 5505 6922 +3 5831 6651 6844 +3 6225 5358 6754 +3 5614 6208 6924 +3 6198 5682 6947 +3 5794 6229 6750 +3 5461 6202 6941 +3 5669 6401 6834 +3 6429 5737 6705 +3 5987 6344 6626 +3 5982 6772 6922 +3 6755 5963 6852 +3 5392 6755 6852 +3 6287 6095 6851 +3 5660 6218 6816 +3 5865 6596 6777 +3 6596 5464 6777 +3 6695 5478 6748 +3 6767 5905 6875 +3 6220 5819 6829 +3 6389 5635 6572 +3 5774 6272 6658 +3 6309 5647 6606 +3 6347 5451 6850 +3 6350 5394 6562 +3 5836 6611 6815 +3 5513 6608 6694 +3 6608 5815 6694 +3 6467 5685 6494 +3 5735 6845 6909 +3 6627 5696 6930 +3 5764 6425 6629 +3 6468 5711 6532 +3 429 6468 6532 +3 5443 6340 6619 +3 5904 6512 6894 +3 6512 5416 6894 +3 6488 5374 6523 +3 5714 6488 6523 +3 5729 6377 6686 +3 6377 5442 6686 +3 6410 5381 6641 +3 344 6234 6788 +3 6317 5722 6902 +3 6384 5446 6638 +3 6212 5589 6929 +3 6273 5665 6687 +3 6269 5478 6695 +3 5441 6249 6817 +3 5771 6406 6801 +3 6406 5662 6801 +3 5828 6354 6577 +3 6472 5451 6525 +3 5927 6316 6786 +3 5629 6484 6561 +3 6842 6020 6927 +3 5822 6842 6927 +3 6417 5659 6544 +3 5729 6476 6855 +3 6393 5620 6726 +3 6457 5688 6653 +3 5951 6457 6653 +3 6264 5594 6820 +3 5583 6237 6825 +3 5704 6472 6525 +3 5434 6473 6630 +3 5761 6839 6939 +3 6839 6021 6939 +3 6404 5616 6680 +3 5856 6358 6695 +3 6293 5379 6702 +3 5697 6293 6702 +3 5964 6325 6659 +3 6325 5467 6659 +3 6263 5727 6846 +3 5476 6263 6846 +3 6453 5780 6793 +3 5509 6453 6793 +3 5720 6431 6609 +3 6431 5456 6609 +3 6257 5723 6932 +3 6336 5643 6615 +3 5918 6249 6771 +3 6270 364 6821 +3 5985 6445 6914 +3 6361 5437 6597 +3 5656 6477 6537 +3 6351 5667 6700 +3 5475 6330 6693 +3 6244 436 6835 +3 6280 5750 6911 +3 5459 6280 6911 +3 6105 6402 6822 +3 6536 5400 6930 +3 5660 6329 6897 +3 5803 6726 6832 +3 6532 5711 6733 +3 6246 5487 6843 +3 6307 5377 6824 +3 5734 6307 6824 +3 6249 5689 6817 +3 5753 6767 6875 +3 5712 6299 6727 +3 5646 6446 6594 +3 5804 6388 6867 +3 6388 5960 6867 +3 5432 6405 6840 +3 5451 6472 6850 +3 5762 6335 6901 +3 6335 5500 6901 +3 6484 5980 6561 +3 6549 5843 6701 +3 5445 6549 6701 +3 6315 5603 6871 +3 5582 6666 6812 +3 6666 5878 6812 +3 6094 6590 6716 +3 6476 5729 6631 +3 5556 6476 6631 +3 5795 6557 6558 +3 6557 5677 6558 +3 6598 5518 6773 +3 5828 6598 6773 +3 6545 5438 6687 +3 5694 6422 6844 +3 6248 5403 6877 +3 5471 6422 6602 +3 5748 6384 6638 +3 5855 6287 6851 +3 6401 5669 6703 +3 6299 5712 6762 +3 6446 5775 6594 +3 5778 6270 6821 +3 5462 6714 6747 +3 5594 6327 6820 +3 6332 274 6715 +3 6564 5454 6918 +3 5426 6256 6892 +3 5681 6300 6776 +3 6639 5659 6640 +3 6040 6639 6640 +3 6463 5741 6697 +3 5475 6463 6697 +3 6277 5889 6819 +3 5603 6335 6871 +3 5598 6311 6753 +3 6385 5750 6790 +3 5383 6385 6790 +3 5785 6276 6838 +3 6364 5648 6691 +3 6509 5754 6602 +3 6621 5918 6711 +3 5901 6535 6740 +3 5457 6427 6813 +3 357 6291 6834 +3 5387 6447 6905 +3 5383 6509 6903 +3 6678 5461 6899 +3 5871 6643 6859 +3 6643 5784 6859 +3 6279 5436 6938 +3 6495 5755 6874 +3 5881 6545 6687 +3 6386 5666 6869 +3 5840 6404 6680 +3 6316 5561 6786 +3 5448 6333 6925 +3 355 6515 6720 +3 6441 5678 6668 +3 5945 6290 6884 +3 5717 6362 6830 +3 6706 5461 6941 +3 5912 6706 6941 +3 5387 6905 6920 +3 5672 6491 6624 +3 5662 6533 6801 +3 5749 6391 6809 +3 6391 5486 6809 +3 6355 5623 6741 +3 5382 6574 6889 +3 6001 6353 6946 +3 5380 6348 6760 +3 6324 5771 6801 +3 5717 6279 6938 +3 6337 5463 6784 +3 5390 6370 6736 +3 5725 6463 6693 +3 6463 5475 6693 +3 6596 5865 6628 +3 5481 6514 6872 +3 5693 6588 6943 +3 6485 5722 6659 +3 5467 6485 6659 +3 6871 5762 6904 +3 6327 5773 6820 +3 5803 6393 6726 +3 5716 6582 6934 +3 6317 5365 6890 +3 6321 5440 6921 +3 6611 5443 6705 +3 5452 6318 6873 +3 6507 5905 6767 +3 5702 6616 6905 +3 6616 5863 6905 +3 6635 5382 6889 +3 5851 6684 6804 +3 6684 5384 6804 +3 5722 6317 6890 +3 5735 6496 6692 +3 6496 5454 6692 +3 5934 6660 6783 +3 6344 5503 6885 +3 5788 6631 6686 +3 6341 5817 6840 +3 5908 6775 6896 +3 5695 6407 6743 +3 6664 5716 6934 +3 5454 6496 6918 +3 6496 5805 6918 +3 6775 5757 6896 +3 5464 6424 6777 +3 6424 5739 6777 +3 6335 5762 6871 +3 6547 5671 6661 +3 6515 5707 6720 +3 5711 6468 6872 +3 6468 5949 6872 +3 6465 5720 6782 +3 5844 6678 6899 +3 6401 356 6834 +3 5726 6698 6699 +3 6698 5802 6699 +3 5686 6596 6628 +3 6444 5691 6798 +3 6505 5473 6731 +3 6362 5717 6849 +3 5536 6527 6854 +3 6333 5705 6925 +3 6679 5770 6681 +3 5744 6679 6681 +3 6463 5725 6747 +3 5688 6457 6878 +3 5719 6391 6813 +3 6434 5674 6774 +3 6402 5730 6822 +3 5896 6374 6933 +3 6374 6043 6933 +3 6671 5795 6697 +3 5384 6484 6804 +3 5386 6465 6782 +3 5674 6580 6774 +3 6580 5788 6774 +3 6353 5884 6946 +3 6493 5891 6833 +3 5946 6487 6935 +3 5894 6789 6868 +3 6789 5759 6868 +3 6422 5471 6844 +3 5747 6769 6785 +3 6769 5857 6785 +3 6631 5729 6686 +3 5447 6415 6856 +3 6599 350 6847 +3 5817 6654 6840 +3 6654 5432 6840 +3 5362 6538 6737 +3 6729 5410 6939 +3 6021 6729 6939 +3 5577 6507 6767 +3 6437 5614 6924 +3 6701 5843 6854 +3 5723 6701 6854 +3 6590 5672 6716 +3 5737 6611 6705 +3 6449 261 6908 +3 5687 6621 6711 +3 5746 6420 6888 +3 5741 6671 6697 +3 5737 6429 6883 +3 6553 5387 6920 +3 5456 6431 6886 +3 5691 6581 6798 +3 6432 5502 6891 +3 6472 5694 6850 +3 6398 5811 6943 +3 5842 6493 6833 +3 6447 5702 6905 +3 5705 6635 6889 +3 5903 6810 6916 +3 6810 5772 6916 +3 5796 6449 6908 +3 6445 5613 6914 +3 5817 6437 6924 +3 5805 6456 6918 +3 5410 6464 6939 +3 6464 5761 6939 +3 6808 5749 6809 +3 5886 6808 6809 +3 5463 6586 6784 +3 6516 5715 6865 +3 6769 5386 6782 +3 5857 6769 6782 +3 6905 5863 6920 +3 6527 5723 6854 +3 6514 5711 6872 +3 5887 6462 6940 +3 6643 384 6826 +3 5784 6643 6826 +3 6912 5756 6913 +3 5933 6912 6913 +3 6581 5791 6798 +3 6161 6526 6931 +3 6749 6028 6778 +3 5908 6650 6775 +3 6509 5704 6903 +3 6669 5804 6867 +3 5366 6669 6867 +3 6650 5367 6775 +3 6660 5585 6783 +3 6611 5737 6815 +3 5824 6757 6807 +3 6757 5476 6807 +3 6563 5453 6893 +3 5765 6563 6893 +3 5742 6599 6847 +3 5398 6651 6860 +3 6651 5831 6860 +3 6526 5782 6931 +3 5723 6527 6932 +3 5804 6763 6797 +3 6763 5813 6797 +3 5505 6579 6922 +3 5696 6536 6930 +3 6574 5844 6889 +3 6576 5498 6940 +3 5706 6749 6778 +3 5513 6694 6927 +3 6694 5822 6927 +3 5811 6655 6943 +3 6655 5693 6943 +3 5909 6664 6934 +3 6579 5764 6922 +3 6741 5718 6880 +3 6582 5507 6934 +3 6936 5768 6937 +3 5935 6936 6937 +3 5824 6807 6870 +3 6881 6146 6882 +3 5721 6881 6882 +3 6852 5963 6904 +3 6698 5408 6942 +3 5802 6698 6942 +3 6807 5823 6870 +3 5762 6852 6904 +3 7188 7107 7226 +3 189 7089 7267 +3 6952 7054 7124 +3 6955 7043 7113 +3 7068 6977 7239 +3 476 477 7068 +3 478 479 7069 +3 6977 7079 7239 +3 7056 6951 7085 +3 7107 6984 7226 +3 7058 6949 7109 +3 7040 6954 7119 +3 6997 7079 7118 +3 7079 6977 7118 +3 6949 7058 7194 +3 7058 7009 7194 +3 7068 477 7199 +3 478 7069 7199 +3 6954 7040 7234 +3 7177 502 7191 +3 496 7178 7190 +3 7069 479 7330 +3 7046 6967 7122 +3 7005 7044 7197 +3 7044 6966 7197 +3 11 457 7125 +3 503 11 7125 +3 7095 7031 7204 +3 7052 6961 7209 +3 7008 7052 7209 +3 6968 7261 7281 +3 7089 7029 7267 +3 7076 6968 7281 +3 187 7088 7183 +3 6964 7095 7204 +3 7063 179 7147 +3 7044 7005 7130 +3 7004 7043 7129 +3 7073 6996 7141 +3 501 502 7177 +3 496 497 7178 +3 7041 6988 7228 +3 7059 6965 7215 +3 7001 7075 7196 +3 6971 7053 7185 +3 508 507 7078 +3 7069 6976 7081 +3 7068 7003 7082 +3 7003 7069 7081 +3 6977 7068 7082 +3 7043 6955 7221 +3 7128 7040 7213 +3 7006 7128 7213 +3 7124 7054 7157 +3 7051 6973 7255 +3 7045 6989 7223 +3 189 188 7089 +3 7075 7001 7206 +3 7020 7155 7185 +3 6981 7123 7208 +3 7073 7141 7287 +3 6957 7081 7151 +3 6981 7093 7123 +3 187 186 7088 +3 7043 7004 7215 +3 7026 7105 7281 +3 6957 7151 7158 +3 6967 7046 7174 +3 6953 7172 7181 +3 461 7071 7090 +3 7061 500 7177 +3 498 7062 7178 +3 6986 7039 7193 +3 6966 7044 7098 +3 7131 183 7188 +3 7039 6986 7173 +3 7102 469 7260 +3 7049 6970 7179 +3 6969 7050 7180 +3 6985 7055 7184 +3 6964 7055 7213 +3 7055 7006 7213 +3 199 7111 7237 +3 6990 7127 7166 +3 508 7078 7164 +3 7047 6963 7162 +3 6961 7052 7214 +3 7004 7059 7215 +3 6965 7099 7215 +3 7099 7043 7215 +3 7095 6964 7213 +3 7040 7095 7213 +3 487 7057 7270 +3 6965 7059 7149 +3 6986 7053 7169 +3 7054 6985 7168 +3 7172 7036 7181 +3 461 462 7071 +3 6985 7054 7201 +3 7053 6986 7193 +3 6962 7039 7325 +3 7064 485 7270 +3 7055 6985 7201 +3 7039 6962 7326 +3 7059 7004 7212 +3 7006 7055 7216 +3 7003 7068 7199 +3 7069 7003 7199 +3 7052 7008 7202 +3 6976 7069 7091 +3 7054 6952 7201 +3 7127 7023 7166 +3 7060 7006 7216 +3 7071 6979 7090 +3 7155 6971 7185 +3 7118 7042 7187 +3 6997 7118 7187 +3 6973 7051 7186 +3 7061 6968 7154 +3 6994 7061 7154 +3 7043 7099 7113 +3 6988 7041 7149 +3 6988 7051 7120 +3 7057 487 7121 +3 7058 7109 7134 +3 7017 7131 7188 +3 6989 7045 7146 +3 7205 6954 7234 +3 7203 6955 7222 +3 6955 7203 7221 +3 6968 7061 7235 +3 6963 7047 7128 +3 7053 6971 7169 +3 7105 7026 7251 +3 7033 7102 7260 +3 7050 6969 7129 +3 6970 7049 7130 +3 6978 7086 7148 +3 7055 6964 7184 +3 6953 7070 7172 +3 7103 7051 7255 +3 6993 7078 7100 +3 7078 6990 7100 +3 193 7160 7228 +3 7219 7010 7278 +3 7010 7102 7278 +3 7051 6988 7186 +3 6954 7205 7247 +3 468 469 7102 +3 7028 7099 7254 +3 7095 7040 7119 +3 6998 7086 7094 +3 6989 7057 7121 +3 179 178 7147 +3 7160 7041 7228 +3 6994 7062 7165 +3 500 7061 7144 +3 7006 7060 7245 +3 7046 7122 7247 +3 463 464 7077 +3 6978 7088 7135 +3 7017 7188 7226 +3 7049 7203 7222 +3 7203 7050 7221 +3 7111 7022 7237 +3 7185 7053 7293 +3 6974 7083 7301 +3 6996 7072 7155 +3 489 7170 7223 +3 6999 7080 7277 +3 199 198 7111 +3 6951 7056 7145 +3 6984 7136 7226 +3 7047 7205 7234 +3 7057 6989 7192 +3 6979 7071 7134 +3 7071 6991 7134 +3 7105 6983 7281 +3 6981 7070 7114 +3 6988 7120 7228 +3 7088 7007 7183 +3 7056 7085 7189 +3 7143 6999 7277 +3 7009 7058 7152 +3 7170 7045 7223 +3 6989 7121 7223 +3 7136 7048 7226 +3 7141 6972 7287 +3 485 486 7270 +3 7150 6999 7266 +3 500 501 7177 +3 497 498 7178 +3 6975 7067 7196 +3 7098 7029 7280 +3 7148 7086 7263 +3 493 7117 7250 +3 7116 213 7251 +3 6967 7174 7262 +3 485 7064 7132 +3 7062 498 7165 +3 460 461 7090 +3 7007 7088 7148 +3 7088 6978 7148 +3 7083 7037 7301 +3 7061 6994 7144 +3 179 7063 7175 +3 7077 7016 7294 +3 7099 6965 7254 +3 7089 7007 7210 +3 7062 6994 7305 +3 7063 6993 7241 +3 7205 7046 7247 +3 6993 7063 7147 +3 7086 6978 7094 +3 7020 7141 7155 +3 7024 7150 7266 +3 6996 7073 7231 +3 203 7072 7153 +3 7059 7212 7304 +3 486 487 7270 +3 465 466 7093 +3 7132 7064 7217 +3 6992 7132 7217 +3 7139 6995 7227 +3 7179 6970 7278 +3 7071 462 7140 +3 6991 7071 7140 +3 7115 7020 7185 +3 7112 509 7164 +3 7089 7210 7280 +3 7001 7124 7157 +3 6978 7135 7285 +3 6977 7080 7118 +3 7137 7077 7294 +3 6969 7180 7289 +3 7060 7216 7321 +3 7088 186 7135 +3 509 508 7164 +3 7075 6975 7196 +3 7141 6996 7155 +3 7083 6974 7246 +3 493 494 7117 +3 214 213 7116 +3 7084 6979 7109 +3 7122 6994 7154 +3 7021 7122 7154 +3 7015 7177 7191 +3 7178 7014 7190 +3 6976 7091 7189 +3 7091 7013 7189 +3 7076 6983 7119 +3 7074 6997 7187 +3 7085 6976 7189 +3 7067 6975 7192 +3 7074 473 7156 +3 7155 7072 7288 +3 476 7068 7239 +3 6966 7098 7280 +3 505 504 7139 +3 6985 7184 7308 +3 7009 7126 7167 +3 7026 7116 7251 +3 7117 7025 7250 +3 7162 6963 7272 +3 7109 6949 7327 +3 7022 7111 7233 +3 197 196 7103 +3 465 7093 7240 +3 7031 7095 7316 +3 7077 464 7240 +3 6949 7202 7327 +3 6980 7098 7113 +3 7022 7233 7325 +3 6956 7075 7206 +3 7072 203 7243 +3 205 7073 7244 +3 7023 7139 7227 +3 7009 7167 7232 +3 7115 7000 7142 +3 7029 7098 7313 +3 7099 7028 7314 +3 6990 7078 7253 +3 458 459 7096 +3 7233 7097 7310 +3 7044 7130 7222 +3 7129 7043 7221 +3 7123 7010 7208 +3 7070 6953 7224 +3 7081 6976 7151 +3 7070 6981 7172 +3 7016 7077 7240 +3 7012 7097 7233 +3 7261 7026 7281 +3 7013 7083 7246 +3 6950 7080 7159 +3 7080 6999 7159 +3 197 7103 7211 +3 473 7074 7248 +3 463 7077 7140 +3 7077 6991 7140 +3 7073 205 7231 +3 7122 7021 7247 +3 7079 6997 7284 +3 6976 7085 7151 +3 7072 6996 7153 +3 186 185 7135 +3 6998 7163 7224 +3 7176 6992 7299 +3 7109 6979 7134 +3 6998 7094 7167 +3 7040 7128 7234 +3 7163 7070 7224 +3 7093 466 7123 +3 7117 7014 7262 +3 7015 7116 7261 +3 505 7139 7307 +3 191 190 7101 +3 7020 7092 7141 +3 7093 7016 7240 +3 6968 7076 7309 +3 7099 6980 7113 +3 6991 7077 7137 +3 7132 6992 7176 +3 6983 7095 7119 +3 495 10 7190 +3 10 496 7190 +3 1 215 7191 +3 502 1 7191 +3 7235 7015 7261 +3 7014 7236 7262 +3 491 492 7104 +3 212 211 7105 +3 208 207 7106 +3 201 200 7108 +3 182 181 7107 +3 6986 7169 7320 +3 7168 6985 7319 +3 7039 7173 7325 +3 7115 7142 7276 +3 470 471 7110 +3 6997 7074 7156 +3 7193 6951 7293 +3 7075 6956 7225 +3 6975 7075 7217 +3 7096 459 7220 +3 184 183 7131 +3 7212 6950 7304 +3 7103 7012 7211 +3 7087 6990 7166 +3 7137 6959 7152 +3 6972 7092 7157 +3 7092 7001 7157 +3 204 203 7153 +3 7153 6996 7231 +3 7082 6957 7143 +3 7157 7054 7168 +3 6972 7157 7168 +3 6983 7076 7281 +3 487 488 7121 +3 195 194 7120 +3 7095 6983 7316 +3 7067 7124 7196 +3 6995 7096 7133 +3 7096 7011 7133 +3 7078 6993 7164 +3 7079 475 7239 +3 7024 7097 7150 +3 7011 7096 7220 +3 466 467 7123 +3 7113 7098 7324 +3 7112 6993 7147 +3 7098 6980 7313 +3 6980 7099 7314 +3 7094 6960 7167 +3 7186 6988 7328 +3 7136 6984 7317 +3 499 500 7144 +3 7074 7187 7289 +3 7127 6990 7253 +3 6979 7084 7282 +3 7174 7025 7262 +3 7124 7067 7321 +3 6952 7124 7321 +3 7085 6951 7198 +3 7002 7085 7198 +3 482 7083 7297 +3 7078 507 7253 +3 473 474 7156 +3 7092 6972 7141 +3 7151 7002 7158 +3 7085 7002 7151 +3 7137 7152 7286 +3 7090 7011 7220 +3 180 7175 7207 +3 6971 7155 7288 +3 7216 6952 7321 +3 480 7091 7330 +3 7144 6994 7165 +3 7225 6956 7276 +3 7098 7044 7324 +3 7053 7193 7293 +3 7080 6977 7277 +3 460 7090 7220 +3 475 7079 7284 +3 6992 7217 7225 +3 7217 7075 7225 +3 7080 6950 7249 +3 6997 7156 7284 +3 7065 7186 7328 +3 7091 7069 7330 +3 7083 7013 7297 +3 195 7120 7323 +3 6977 7082 7277 +3 7083 482 7230 +3 483 7176 7230 +3 6957 7082 7242 +3 7081 6957 7242 +3 7082 7003 7242 +3 7003 7081 7242 +3 7101 190 7267 +3 191 7101 7268 +3 484 485 7132 +3 7037 7083 7230 +3 7089 188 7183 +3 7108 200 7237 +3 6959 7126 7152 +3 7126 7009 7152 +3 7104 492 7250 +3 212 7105 7251 +3 208 7106 7252 +3 491 7104 7264 +3 7105 211 7265 +3 7000 7185 7293 +3 7030 7162 7272 +3 7033 7179 7278 +3 7058 7134 7286 +3 7134 6991 7286 +3 6962 7233 7310 +3 6993 7100 7241 +3 7066 7225 7276 +3 7084 6958 7218 +3 6958 7084 7256 +3 7106 207 7273 +3 201 7108 7274 +3 470 7110 7260 +3 7120 7051 7323 +3 6958 7087 7166 +3 7192 6989 7318 +3 7007 7148 7210 +3 7148 7038 7210 +3 472 473 7248 +3 7052 7136 7317 +3 203 202 7243 +3 206 205 7244 +3 7007 7089 7183 +3 7097 6973 7150 +3 7011 7090 7282 +3 7091 480 7195 +3 210 209 7138 +3 183 182 7188 +3 6953 7086 7224 +3 7114 7070 7163 +3 7087 7008 7209 +3 7110 471 7271 +3 7162 6982 7205 +3 7047 7162 7205 +3 181 180 7207 +3 6990 7087 7298 +3 7013 7091 7195 +3 7086 6998 7224 +3 462 463 7140 +3 193 192 7160 +3 7090 6979 7282 +3 489 490 7170 +3 7086 6953 7263 +3 7087 6958 7256 +3 7008 7087 7256 +3 7001 7092 7206 +3 7180 7032 7289 +3 7051 7103 7323 +3 7103 196 7323 +3 6961 7100 7298 +3 7125 6995 7322 +3 7176 7037 7230 +3 479 480 7330 +3 180 179 7175 +3 7029 7089 7280 +3 7066 7142 7301 +3 7142 6974 7301 +3 483 484 7176 +3 6973 7097 7255 +3 7097 7012 7255 +3 6987 7180 7203 +3 7179 6987 7203 +3 7049 7179 7203 +3 7180 7050 7203 +3 7101 7267 7313 +3 7268 7101 7314 +3 6949 7136 7202 +3 7136 7052 7202 +3 7092 7020 7291 +3 6982 7174 7205 +3 7174 7046 7205 +3 7096 6995 7257 +3 6959 7114 7163 +3 6995 7139 7322 +3 7115 6956 7291 +3 7020 7115 7291 +3 506 505 7307 +3 457 458 7257 +3 7105 7265 7316 +3 7264 7104 7315 +3 7016 7093 7296 +3 7093 6981 7296 +3 6960 7094 7302 +3 194 193 7228 +3 7252 7106 7308 +3 7104 7250 7306 +3 7263 6953 7300 +3 7094 6978 7285 +3 6993 7112 7164 +3 7135 7018 7285 +3 7106 7273 7319 +3 7274 7108 7320 +3 7118 7080 7249 +3 6973 7186 7279 +3 7175 7019 7207 +3 7260 7110 7311 +3 6969 7187 7238 +3 7037 7176 7299 +3 6994 7122 7305 +3 7060 7146 7245 +3 7146 6963 7245 +3 6995 7133 7227 +3 475 476 7239 +3 7067 7192 7318 +3 7056 7246 7292 +3 7125 457 7257 +3 481 482 7297 +3 488 489 7223 +3 7127 506 7307 +3 7128 7047 7234 +3 7123 467 7200 +3 7010 7123 7200 +3 7146 7045 7272 +3 6963 7146 7272 +3 468 7102 7200 +3 7102 7010 7200 +3 7186 7065 7279 +3 7149 7041 7254 +3 6965 7149 7254 +3 7108 7237 7295 +3 182 7107 7188 +3 7138 209 7252 +3 7027 7138 7252 +3 188 187 7183 +3 7138 7031 7265 +3 210 7138 7265 +3 6975 7217 7303 +3 7100 6990 7298 +3 6962 7161 7326 +3 7187 7042 7238 +3 7136 6949 7194 +3 7048 7136 7194 +3 7130 7049 7222 +3 7050 7129 7221 +3 7107 181 7207 +3 7112 7147 7331 +3 6998 7126 7163 +3 6989 7146 7318 +3 7187 6969 7289 +3 6988 7149 7328 +3 6951 7193 7198 +3 7193 7039 7198 +3 7000 7115 7185 +3 458 7096 7257 +3 7100 6961 7241 +3 7110 7271 7312 +3 498 499 7165 +3 7012 7111 7211 +3 7111 198 7211 +3 7097 7024 7310 +3 7019 7175 7283 +3 6999 7143 7266 +3 507 506 7253 +3 7139 7023 7307 +3 7102 7033 7278 +3 6951 7145 7293 +3 7012 7103 7255 +3 7146 7060 7318 +3 7175 7063 7283 +3 480 481 7195 +3 6984 7107 7290 +3 7111 7012 7233 +3 6995 7125 7257 +3 6983 7105 7316 +3 7142 7000 7292 +3 6999 7150 7279 +3 7126 6959 7163 +3 7048 7194 7232 +3 7194 7009 7232 +3 7018 7131 7171 +3 7084 7109 7327 +3 7126 6998 7167 +3 7036 7208 7219 +3 506 7127 7253 +3 7038 7148 7263 +3 7184 7027 7308 +3 7000 7145 7292 +3 7084 7218 7282 +3 477 478 7199 +3 467 468 7200 +3 7210 6966 7280 +3 7056 7189 7246 +3 7189 7013 7246 +3 494 495 7258 +3 215 214 7259 +3 6953 7181 7300 +3 7159 6999 7279 +3 482 483 7230 +3 7149 7059 7328 +3 6950 7159 7304 +3 7159 7065 7304 +3 7076 7119 7229 +3 7119 6954 7229 +3 6958 7133 7218 +3 7133 7011 7218 +3 7038 7197 7210 +3 7197 6966 7210 +3 7131 7017 7171 +3 198 197 7211 +3 7130 7005 7182 +3 6970 7130 7182 +3 7048 7232 7275 +3 6970 7219 7278 +3 7124 7001 7196 +3 7055 7201 7216 +3 7201 6952 7216 +3 484 7132 7176 +3 459 460 7220 +3 7184 6964 7204 +3 7027 7184 7204 +3 7014 7117 7258 +3 7116 7015 7259 +3 7117 494 7258 +3 214 7116 7259 +3 6970 7182 7219 +3 7182 7036 7219 +3 7217 7064 7303 +3 7016 7114 7294 +3 7114 6959 7294 +3 7246 6974 7292 +3 205 204 7231 +3 7120 194 7228 +3 509 7112 7329 +3 7131 7018 7269 +3 184 7131 7269 +3 6956 7115 7276 +3 7169 7035 7320 +3 7034 7168 7319 +3 7116 7026 7261 +3 7025 7117 7262 +3 7208 7010 7219 +3 7042 7118 7249 +3 7108 7295 7320 +3 7295 6986 7320 +3 7114 7016 7296 +3 6981 7114 7296 +3 499 7144 7165 +3 474 475 7284 +3 200 199 7237 +3 6955 7113 7324 +3 464 465 7240 +3 7121 488 7223 +3 7209 6961 7298 +3 7145 7056 7292 +3 7129 6969 7238 +3 7076 7229 7309 +3 7229 7021 7309 +3 471 472 7271 +3 7019 7214 7317 +3 7128 7006 7245 +3 492 493 7250 +3 213 212 7251 +3 209 208 7252 +3 504 503 7322 +3 7024 7158 7161 +3 469 470 7260 +3 202 201 7274 +3 207 206 7273 +3 490 491 7264 +3 211 210 7265 +3 192 191 7268 +3 190 189 7267 +3 185 184 7269 +3 7167 6960 7232 +3 7031 7138 7204 +3 7138 7027 7204 +3 6987 7311 7312 +3 7311 7110 7312 +3 7133 6958 7227 +3 7232 6960 7275 +3 7306 6982 7315 +3 7104 7306 7315 +3 7158 7002 7161 +3 7290 7019 7317 +3 7018 7135 7269 +3 7135 185 7269 +3 7308 7106 7319 +3 6985 7308 7319 +3 7267 7029 7313 +3 7028 7268 7314 +3 7248 7074 7289 +3 7032 7248 7289 +3 5 509 7329 +3 177 5 7329 +3 7004 7129 7238 +3 196 195 7323 +3 6968 7235 7261 +3 7236 6967 7262 +3 178 177 7331 +3 503 7125 7322 +3 6963 7128 7245 +3 7101 7313 7314 +3 7313 6980 7314 +3 7045 7170 7272 +3 7170 7030 7272 +3 7082 7143 7277 +3 7034 7244 7287 +3 7244 7073 7287 +3 7072 7243 7288 +3 7243 7035 7288 +3 7041 7160 7254 +3 7160 7028 7254 +3 7265 7031 7316 +3 7030 7264 7315 +3 7212 7004 7238 +3 7042 7212 7238 +3 7038 7263 7300 +3 7273 7034 7319 +3 7035 7274 7320 +3 7005 7181 7182 +3 7181 7036 7182 +3 7036 7172 7208 +3 7027 7252 7308 +3 7250 7025 7306 +3 7160 192 7268 +3 7028 7160 7268 +3 7008 7256 7327 +3 7256 7084 7327 +3 7122 6967 7305 +3 6950 7212 7249 +3 7212 7042 7249 +3 7033 7260 7311 +3 7158 7024 7266 +3 6957 7158 7266 +3 7014 7178 7236 +3 7178 7062 7236 +3 7177 7015 7235 +3 7061 7177 7235 +3 7170 490 7264 +3 7030 7170 7264 +3 6991 7137 7286 +3 7237 7022 7295 +3 7013 7195 7297 +3 7023 7127 7307 +3 177 7329 7331 +3 7329 7112 7331 +3 204 7153 7231 +3 7142 7066 7276 +3 7172 6981 7208 +3 495 7190 7258 +3 7191 215 7259 +3 6959 7137 7294 +3 7057 7192 7303 +3 7192 6975 7303 +3 7271 7032 7312 +3 6958 7166 7227 +3 7143 6957 7266 +3 7150 6973 7279 +3 7225 7066 7299 +3 6992 7225 7299 +3 7166 7023 7227 +3 7202 7008 7327 +3 7168 7034 7287 +3 6972 7168 7287 +3 7169 6971 7288 +3 7035 7169 7288 +3 7139 504 7322 +3 6974 7142 7292 +3 7226 7048 7275 +3 7233 6962 7325 +3 7145 7000 7293 +3 7171 7017 7275 +3 7152 7058 7286 +3 7018 7171 7302 +3 7065 7159 7279 +3 7024 7161 7310 +3 7156 474 7284 +3 7229 6954 7247 +3 6960 7171 7275 +3 7236 7062 7305 +3 6967 7236 7305 +3 7190 7014 7258 +3 7015 7191 7259 +3 7147 178 7331 +3 7107 7207 7290 +3 7017 7226 7275 +3 7161 6962 7310 +3 7206 7092 7291 +3 7214 7019 7283 +3 6982 7162 7315 +3 7162 7030 7315 +3 7021 7229 7247 +3 7154 6968 7309 +3 7021 7154 7309 +3 6961 7214 7283 +3 7022 7173 7295 +3 7173 6986 7295 +3 7171 6960 7302 +3 472 7248 7271 +3 7181 7005 7300 +3 7174 6982 7306 +3 7025 7174 7306 +3 7180 6987 7312 +3 6987 7179 7311 +3 7179 7033 7311 +3 7032 7180 7312 +3 7241 6961 7283 +3 7243 202 7274 +3 206 7244 7273 +3 6956 7206 7291 +3 7207 7019 7290 +3 7161 7002 7326 +3 7005 7197 7300 +3 7218 7011 7282 +3 7244 7034 7273 +3 7035 7243 7274 +3 7195 481 7297 +3 7002 7198 7326 +3 7198 7039 7326 +3 7248 7032 7271 +3 7044 7222 7324 +3 7222 6955 7324 +3 7173 7022 7325 +3 7197 7038 7300 +3 7087 7209 7298 +3 7063 7241 7283 +3 7270 7057 7303 +3 7064 7270 7303 +3 7214 7052 7317 +3 7299 7066 7301 +3 7037 7299 7301 +3 7285 7018 7302 +3 7304 7065 7328 +3 7094 7285 7302 +3 6984 7290 7317 +3 7067 7318 7321 +3 7318 7060 7321 +3 7059 7304 7328 +3 7580 7489 7617 +3 7335 7441 7443 +3 7435 7334 7575 +3 7424 7366 7533 +3 7389 7435 7575 +3 7430 7333 7502 +3 552 551 7439 +3 550 7467 7554 +3 7489 7367 7617 +3 519 7428 7527 +3 7424 543 7579 +3 7425 530 7578 +3 7443 7441 7702 +3 7 286 7508 +3 556 7 7508 +3 320 321 7447 +3 7428 519 7535 +3 7483 7415 7594 +3 7366 7424 7539 +3 7362 7505 7583 +3 512 7448 7548 +3 7447 321 7546 +3 7429 7389 7517 +3 7460 7360 7628 +3 7360 7537 7628 +3 295 296 7442 +3 7352 7483 7594 +3 7437 7370 7623 +3 561 560 7451 +3 7481 7413 7593 +3 7335 7443 7696 +3 7515 7410 7565 +3 7362 7470 7505 +3 7389 7429 7604 +3 550 549 7467 +3 530 7425 7543 +3 511 512 7548 +3 7438 7395 7602 +3 7370 7437 7631 +3 7351 7481 7593 +3 7423 7346 7553 +3 7338 7434 7605 +3 7346 7423 7635 +3 7442 296 7475 +3 7339 7515 7565 +3 310 7518 7581 +3 7519 299 7580 +3 7430 7481 7603 +3 7481 7351 7603 +3 7486 537 7643 +3 534 7487 7642 +3 7440 7358 7477 +3 543 7424 7533 +3 7433 7353 7572 +3 7457 510 7548 +3 7354 7434 7577 +3 527 526 7450 +3 7434 7388 7605 +3 7368 7435 7573 +3 7352 7435 7604 +3 7435 7389 7604 +3 313 314 7446 +3 7434 7338 7592 +3 561 7451 7559 +3 552 7439 7595 +3 7439 7390 7598 +3 7483 7352 7604 +3 7429 7483 7604 +3 7351 7436 7603 +3 7436 7388 7603 +3 7362 7583 7637 +3 7388 7434 7608 +3 7434 7354 7608 +3 7438 7602 7666 +3 527 7450 7478 +3 7490 7581 7649 +3 7439 7598 7630 +3 7358 7442 7475 +3 7361 7436 7569 +3 7433 7369 7592 +3 7455 7362 7637 +3 510 511 7548 +3 7492 7354 7606 +3 7337 7440 7477 +3 7368 7431 7542 +3 290 291 7452 +3 7514 7429 7614 +3 7467 7390 7554 +3 7436 7361 7514 +3 7369 7434 7592 +3 7334 7435 7542 +3 7625 7372 7635 +3 7454 7364 7620 +3 7435 7368 7542 +3 7388 7436 7605 +3 7342 7456 7618 +3 7366 7453 7533 +3 7446 7357 7488 +3 7431 7368 7649 +3 7364 7549 7620 +3 7338 7514 7614 +3 7419 7492 7606 +3 7492 7430 7603 +3 7388 7492 7603 +3 7369 7433 7572 +3 7370 7479 7623 +3 532 7471 7591 +3 290 7452 7491 +3 7557 7342 7618 +3 7481 7430 7502 +3 7333 7430 7627 +3 7518 7404 7581 +3 7405 7519 7580 +3 313 7446 7488 +3 7337 7444 7506 +3 7347 7466 7509 +3 7466 7383 7509 +3 7434 7369 7577 +3 7449 514 7536 +3 7469 7386 7597 +3 7379 7447 7546 +3 7595 7439 7630 +3 7435 7352 7573 +3 7472 7357 7516 +3 7398 7595 7630 +3 7417 7486 7643 +3 7487 7416 7642 +3 7353 7433 7517 +3 7450 7363 7478 +3 7445 7366 7539 +3 7375 7451 7484 +3 7451 7373 7484 +3 7598 7350 7630 +3 7458 7364 7671 +3 7607 7396 7660 +3 7397 7606 7659 +3 7535 7375 7636 +3 7396 7486 7660 +3 7487 7397 7659 +3 7368 7490 7649 +3 538 537 7486 +3 534 533 7487 +3 322 323 7463 +3 7513 7411 7532 +3 7373 7513 7532 +3 532 531 7471 +3 7503 7458 7671 +3 7386 7560 7597 +3 7464 7385 7473 +3 7383 7466 7472 +3 7428 7535 7636 +3 7371 7448 7476 +3 7448 7377 7476 +3 315 316 7461 +3 7436 7351 7569 +3 7602 7336 7666 +3 7452 7360 7491 +3 7359 7467 7522 +3 7357 7446 7516 +3 7446 7374 7516 +3 7405 7580 7617 +3 7507 7372 7625 +3 319 7437 7623 +3 522 521 7458 +3 545 544 7453 +3 7437 319 7570 +3 7366 7445 7499 +3 7346 7474 7512 +3 7474 7384 7512 +3 7502 7432 7617 +3 7363 7444 7500 +3 7409 7480 7680 +3 7367 7502 7617 +3 7480 7619 7680 +3 7461 7403 7520 +3 7358 7465 7477 +3 7356 7443 7631 +3 520 519 7527 +3 7422 7551 7650 +3 7390 7439 7554 +3 7439 551 7554 +3 7520 7403 7679 +3 7390 7467 7540 +3 7467 7359 7540 +3 7445 7341 7563 +3 7383 7445 7563 +3 7410 7515 7571 +3 7410 7571 7681 +3 7462 7339 7565 +3 7395 7438 7544 +3 7461 316 7634 +3 7452 7381 7537 +3 7360 7452 7537 +3 7528 7378 7613 +3 7468 7349 7484 +3 7373 7468 7484 +3 519 518 7535 +3 7446 314 7529 +3 7465 7382 7477 +3 547 546 7469 +3 7452 291 7574 +3 7384 7474 7541 +3 543 542 7579 +3 530 529 7578 +3 7466 7357 7472 +3 7359 7464 7473 +3 7358 7440 7600 +3 554 553 7480 +3 525 524 7459 +3 7442 7372 7507 +3 295 7442 7507 +3 7359 7473 7540 +3 7459 7402 7526 +3 7472 7516 7666 +3 289 290 7491 +3 7462 7379 7525 +3 7339 7462 7525 +3 7480 553 7595 +3 7374 7446 7529 +3 541 540 7470 +3 7440 7337 7541 +3 7471 7397 7591 +3 7354 7577 7659 +3 7505 7396 7583 +3 514 515 7536 +3 7572 7353 7660 +3 7359 7522 7656 +3 7421 7499 7602 +3 7499 7336 7602 +3 7444 7363 7506 +3 7458 7387 7549 +3 7364 7458 7549 +3 7371 7476 7525 +3 7495 562 7559 +3 7371 7525 7695 +3 7453 7366 7547 +3 7386 7453 7547 +3 7442 7358 7600 +3 7467 549 7522 +3 7395 7564 7582 +3 562 561 7559 +3 7441 7335 7596 +3 7360 7460 7493 +3 7531 7350 7538 +3 7410 7531 7538 +3 7411 7528 7613 +3 7441 7504 7702 +3 7372 7442 7600 +3 7449 7377 7663 +3 7419 7497 7627 +3 7455 7334 7588 +3 7392 7455 7588 +3 522 7458 7503 +3 7463 323 7624 +3 7422 7506 7551 +3 545 7453 7566 +3 7443 7356 7530 +3 547 7469 7646 +3 7462 7565 7670 +3 528 527 7478 +3 296 297 7475 +3 7403 7461 7634 +3 7364 7454 7496 +3 7362 7455 7498 +3 7365 7456 7497 +3 7339 7476 7515 +3 7476 7377 7515 +3 7384 7550 7585 +3 558 557 7528 +3 7392 7509 7563 +3 7395 7510 7564 +3 7394 7511 7562 +3 7468 7373 7532 +3 7497 7333 7627 +3 7356 7631 7676 +3 7340 7493 7699 +3 324 7457 7624 +3 7448 512 7545 +3 7512 7384 7585 +3 7368 7573 7684 +3 7423 7625 7635 +3 7383 7472 7552 +3 7601 7340 7699 +3 7483 7429 7514 +3 7392 7563 7612 +3 7550 7384 7675 +3 7394 7562 7622 +3 7341 7445 7539 +3 312 313 7488 +3 7541 7474 7677 +3 7415 7483 7690 +3 7373 7451 7638 +3 287 288 7482 +3 7448 7371 7548 +3 7337 7506 7675 +3 7429 7517 7614 +3 7444 7337 7626 +3 7540 7473 7661 +3 7398 7480 7595 +3 7445 7383 7552 +3 7504 7370 7702 +3 7447 7379 7651 +3 7453 7386 7566 +3 317 318 7479 +3 7355 7449 7680 +3 7397 7471 7584 +3 7471 7365 7584 +3 7457 7371 7624 +3 7361 7483 7514 +3 7385 7561 7596 +3 525 7459 7534 +3 7561 7441 7596 +3 549 548 7522 +3 7401 7500 7557 +3 7500 7342 7557 +3 7371 7463 7624 +3 7469 7406 7646 +3 7459 7376 7534 +3 7413 7481 7683 +3 7514 7338 7605 +3 7436 7514 7605 +3 7450 526 7534 +3 7376 7450 7534 +3 7470 540 7505 +3 7458 521 7609 +3 558 7528 7682 +3 304 305 7485 +3 7495 7375 7535 +3 7551 7376 7650 +3 7381 7452 7574 +3 7454 7332 7615 +3 7393 7454 7615 +3 7460 7332 7599 +3 7391 7460 7599 +3 7367 7481 7502 +3 7361 7569 7689 +3 7488 7357 7655 +3 300 301 7489 +3 308 309 7490 +3 7349 7468 7589 +3 7468 7391 7589 +3 320 7447 7570 +3 7371 7457 7548 +3 7424 7579 7632 +3 7377 7449 7571 +3 7449 7355 7571 +3 7356 7462 7670 +3 7377 7448 7545 +3 7472 7336 7552 +3 7581 7404 7649 +3 7382 7558 7626 +3 323 324 7624 +3 7363 7450 7551 +3 7450 7376 7551 +3 536 535 7494 +3 7474 7346 7635 +3 523 522 7503 +3 7558 7444 7626 +3 7455 7392 7612 +3 7526 7402 7674 +3 7374 7461 7520 +3 7549 7387 7665 +3 7358 7475 7657 +3 7400 7498 7632 +3 7482 288 7611 +3 310 311 7518 +3 298 299 7519 +3 7343 7550 7650 +3 7497 7419 7584 +3 7459 524 7629 +3 7402 7459 7629 +3 514 7449 7663 +3 7376 7459 7526 +3 7453 544 7533 +3 315 7461 7529 +3 7422 7550 7675 +3 7520 7344 7544 +3 7461 7374 7529 +3 7479 7403 7634 +3 7504 7441 7561 +3 7495 7535 7703 +3 7473 7385 7596 +3 7365 7497 7584 +3 7475 7408 7657 +3 541 7470 7668 +3 7378 7482 7521 +3 7482 7399 7521 +3 7468 7532 7601 +3 7451 7375 7559 +3 7377 7545 7663 +3 7346 7586 7688 +3 7399 7482 7611 +3 540 539 7505 +3 7530 7380 7555 +3 7501 7423 7553 +3 7483 7361 7690 +3 7464 7345 7564 +3 7465 7348 7562 +3 7382 7465 7562 +3 7385 7464 7564 +3 7481 7367 7683 +3 7460 7391 7699 +3 7513 7373 7638 +3 510 7457 7693 +3 7457 324 7693 +3 7491 7360 7662 +3 7506 7422 7675 +3 7387 7458 7609 +3 7354 7492 7608 +3 12 555 7610 +3 516 12 7610 +3 7526 7343 7650 +3 7463 7379 7546 +3 322 7463 7546 +3 7476 7339 7525 +3 7451 560 7638 +3 7619 7531 7681 +3 7432 7502 7587 +3 7407 7488 7655 +3 7386 7469 7566 +3 7469 546 7566 +3 7398 7531 7619 +3 7408 7475 7648 +3 7475 297 7648 +3 7502 7333 7587 +3 7438 7516 7664 +3 7516 7374 7664 +3 7547 7421 7560 +3 7386 7547 7560 +3 317 7479 7634 +3 7579 7400 7632 +3 512 513 7545 +3 7463 7371 7695 +3 7520 7544 7664 +3 7651 7356 7676 +3 7499 7445 7552 +3 7478 7363 7672 +3 7334 7455 7637 +3 294 295 7507 +3 7462 7356 7651 +3 7456 7342 7697 +3 7456 7365 7618 +3 7332 7454 7620 +3 7454 7393 7652 +3 7471 531 7543 +3 7583 7420 7637 +3 7631 7437 7676 +3 7553 7346 7688 +3 7418 7549 7665 +3 7485 305 7645 +3 304 7485 7644 +3 7403 7479 7678 +3 7366 7499 7547 +3 7499 7421 7547 +3 7345 7464 7700 +3 7530 7555 7696 +3 7530 7356 7670 +3 7390 7540 7598 +3 7540 7426 7598 +3 7498 7341 7632 +3 7498 7400 7673 +3 7344 7510 7544 +3 7510 7395 7544 +3 308 7490 7639 +3 7489 301 7640 +3 7447 7651 7676 +3 7577 7416 7659 +3 7417 7572 7660 +3 7379 7463 7695 +3 528 7478 7669 +3 7375 7484 7636 +3 7498 7455 7612 +3 7501 292 7698 +3 536 7494 7643 +3 7494 535 7642 +3 7332 7460 7628 +3 544 543 7533 +3 7410 7538 7565 +3 7379 7462 7651 +3 7336 7499 7552 +3 7449 7536 7680 +3 292 293 7698 +3 7350 7598 7633 +3 7470 7400 7668 +3 302 303 7523 +3 306 307 7524 +3 7522 7406 7656 +3 314 315 7529 +3 7488 7407 7647 +3 312 7488 7647 +3 309 310 7581 +3 299 300 7580 +3 7500 7444 7558 +3 7391 7468 7601 +3 318 319 7623 +3 292 7501 7574 +3 7430 7492 7627 +3 7466 7347 7691 +3 7348 7465 7692 +3 7406 7469 7597 +3 7357 7466 7655 +3 7464 7359 7656 +3 7465 7358 7657 +3 7477 7382 7626 +3 7508 7378 7694 +3 7365 7471 7701 +3 7335 7473 7596 +3 293 294 7625 +3 526 525 7534 +3 7557 7425 7578 +3 7401 7557 7578 +3 7344 7504 7561 +3 291 292 7574 +3 7485 7645 7690 +3 7644 7485 7689 +3 7492 7388 7608 +3 7478 7401 7669 +3 7482 7378 7641 +3 7333 7497 7658 +3 7480 7409 7653 +3 554 7480 7653 +3 7342 7500 7558 +3 7378 7521 7613 +3 7378 7528 7694 +3 559 558 7682 +3 286 287 7641 +3 7470 7362 7673 +3 7400 7470 7673 +3 7343 7496 7652 +3 7549 7418 7620 +3 531 530 7543 +3 7489 7640 7683 +3 7639 7490 7684 +3 7337 7477 7626 +3 7336 7472 7666 +3 7473 7335 7661 +3 7375 7495 7559 +3 7643 7494 7686 +3 7494 7642 7687 +3 521 520 7609 +3 7564 7345 7582 +3 319 320 7570 +3 7508 286 7641 +3 7491 7399 7611 +3 289 7491 7611 +3 523 7503 7629 +3 7503 7402 7629 +3 7381 7501 7553 +3 7513 559 7682 +3 7505 539 7590 +3 7396 7505 7590 +3 7479 318 7623 +3 7671 7496 7674 +3 7524 307 7639 +3 302 7523 7640 +3 7480 7398 7619 +3 538 7486 7590 +3 7397 7487 7591 +3 7487 533 7591 +3 7486 7396 7590 +3 7412 7524 7639 +3 7523 7413 7640 +3 7516 7438 7666 +3 300 7489 7580 +3 7490 309 7581 +3 321 322 7546 +3 7532 7340 7601 +3 7539 7424 7632 +3 7401 7478 7672 +3 7479 7370 7678 +3 7598 7426 7633 +3 7384 7541 7675 +3 7414 7523 7644 +3 7524 7415 7645 +3 7523 303 7644 +3 306 7524 7645 +3 7517 7433 7614 +3 7399 7491 7662 +3 551 550 7554 +3 7402 7671 7674 +3 7382 7511 7558 +3 7385 7510 7561 +3 7474 7635 7677 +3 7635 7372 7677 +3 7501 7381 7574 +3 287 7482 7641 +3 7506 7363 7551 +3 520 7527 7609 +3 560 559 7638 +3 7484 7349 7636 +3 7512 7393 7586 +3 7346 7512 7586 +3 7528 7411 7682 +3 546 545 7566 +3 7492 7419 7627 +3 7486 7417 7660 +3 7416 7487 7659 +3 7537 7427 7628 +3 542 541 7668 +3 529 528 7669 +3 7364 7496 7671 +3 7592 7338 7614 +3 7433 7592 7614 +3 7378 7508 7641 +3 7367 7489 7683 +3 7490 7368 7684 +3 7341 7498 7612 +3 7511 7342 7558 +3 7414 7569 7593 +3 7587 7394 7622 +3 7432 7587 7622 +3 7392 7588 7621 +3 7588 7431 7621 +3 7569 7351 7593 +3 7510 7344 7561 +3 7518 7407 7568 +3 7408 7519 7567 +3 7556 7428 7636 +3 7426 7540 7661 +3 7493 7340 7685 +3 7493 7460 7699 +3 7509 7383 7563 +3 7511 7382 7562 +3 7510 7385 7564 +3 7349 7556 7636 +3 7360 7493 7662 +3 559 7513 7638 +3 7496 7454 7652 +3 7560 7345 7597 +3 7550 7343 7585 +3 539 538 7590 +3 533 532 7591 +3 7573 7412 7684 +3 7538 7350 7633 +3 7497 7456 7658 +3 7586 7393 7615 +3 7427 7586 7615 +3 553 552 7595 +3 7527 7428 7556 +3 293 7625 7698 +3 7362 7498 7673 +3 7440 7541 7677 +3 7387 7527 7556 +3 7515 7377 7571 +3 513 514 7663 +3 7519 7405 7567 +3 7404 7518 7568 +3 7571 7355 7681 +3 7573 7352 7594 +3 7412 7573 7594 +3 7517 7389 7576 +3 7353 7517 7576 +3 7432 7622 7654 +3 7606 7354 7659 +3 7353 7607 7660 +3 7532 7411 7613 +3 7340 7532 7613 +3 7393 7512 7585 +3 7387 7556 7665 +3 7582 7421 7602 +3 7395 7582 7602 +3 288 289 7611 +3 7576 7420 7607 +3 7353 7576 7607 +3 7525 7379 7695 +3 7563 7341 7612 +3 562 7495 7704 +3 7587 7333 7658 +3 7407 7518 7647 +3 7519 7408 7648 +3 298 7519 7648 +3 7518 311 7647 +3 7425 7557 7618 +3 7363 7500 7672 +3 7500 7401 7672 +3 7569 7414 7689 +3 7589 7391 7599 +3 7418 7589 7599 +3 7496 7343 7674 +3 7585 7343 7652 +3 3 510 7693 +3 324 3 7693 +3 7550 7422 7650 +3 524 523 7629 +3 7538 7380 7565 +3 555 554 7653 +3 7420 7583 7607 +3 7583 7396 7607 +3 7397 7584 7606 +3 7584 7419 7606 +3 7423 7501 7698 +3 7334 7542 7588 +3 7542 7431 7588 +3 7703 517 7704 +3 7495 7703 7704 +3 7355 7619 7681 +3 316 317 7634 +3 7537 7381 7688 +3 7427 7537 7688 +3 307 308 7639 +3 301 302 7640 +3 7347 7509 7621 +3 7509 7392 7621 +3 557 556 7694 +3 535 534 7642 +3 537 536 7643 +3 303 304 7644 +3 305 306 7645 +3 548 547 7646 +3 297 298 7648 +3 311 312 7647 +3 7562 7348 7622 +3 7658 7456 7697 +3 7616 7347 7621 +3 7431 7616 7621 +3 7415 7524 7594 +3 7523 7414 7593 +3 7413 7523 7593 +3 7524 7412 7594 +3 294 7507 7625 +3 7369 7686 7687 +3 7686 7494 7687 +3 7622 7348 7654 +3 7402 7503 7671 +3 7406 7522 7646 +3 7522 548 7646 +3 515 516 7667 +3 7521 7340 7613 +3 7619 7355 7680 +3 7645 7415 7690 +3 7414 7644 7689 +3 518 517 7703 +3 7335 7555 7661 +3 7555 7426 7661 +3 7394 7658 7697 +3 7471 7543 7701 +3 7342 7511 7697 +3 7370 7504 7678 +3 7504 7403 7678 +3 13 562 7704 +3 517 13 7704 +3 7504 7344 7679 +3 7403 7504 7679 +3 7527 7387 7609 +3 556 7508 7694 +3 7380 7538 7633 +3 7586 7427 7688 +3 7361 7689 7690 +3 7689 7485 7690 +3 7579 542 7668 +3 7578 529 7669 +3 7640 7413 7683 +3 7412 7639 7684 +3 7575 7420 7576 +3 7389 7575 7576 +3 7345 7560 7582 +3 7560 7421 7582 +3 7599 7332 7620 +3 7418 7599 7620 +3 7531 7398 7630 +3 7575 7334 7637 +3 7420 7575 7637 +3 7615 7332 7628 +3 7427 7615 7628 +3 7642 7416 7687 +3 7417 7643 7686 +3 7350 7531 7630 +3 7565 7380 7670 +3 7340 7521 7685 +3 7374 7520 7664 +3 7555 7380 7633 +3 7343 7526 7674 +3 7376 7526 7650 +3 7511 7394 7697 +3 7600 7440 7677 +3 7372 7600 7677 +3 7411 7513 7682 +3 7409 7536 7667 +3 7344 7520 7679 +3 7341 7539 7632 +3 7616 7431 7649 +3 7521 7399 7685 +3 7568 7347 7616 +3 7404 7568 7616 +3 7380 7530 7670 +3 7536 515 7667 +3 7531 7410 7681 +3 7528 557 7694 +3 7443 7530 7696 +3 7426 7555 7633 +3 7617 7432 7654 +3 7536 7409 7680 +3 7555 7335 7696 +3 7391 7601 7699 +3 7567 7405 7654 +3 7556 7349 7665 +3 7544 7438 7664 +3 7545 513 7663 +3 7568 7407 7691 +3 7408 7567 7692 +3 7541 7337 7675 +3 7535 518 7703 +3 7570 7447 7676 +3 7406 7597 7700 +3 7348 7567 7654 +3 7610 555 7653 +3 7625 7423 7698 +3 7349 7589 7665 +3 7393 7585 7652 +3 7543 7425 7701 +3 7405 7617 7654 +3 7394 7587 7658 +3 7610 7409 7667 +3 7381 7553 7688 +3 7631 7443 7702 +3 7370 7631 7702 +3 7401 7578 7669 +3 7400 7579 7668 +3 7404 7616 7649 +3 7437 7570 7676 +3 7409 7610 7653 +3 7656 7406 7700 +3 7589 7418 7665 +3 7572 7417 7686 +3 7369 7572 7686 +3 7416 7577 7687 +3 7577 7369 7687 +3 7662 7493 7685 +3 7399 7662 7685 +3 7347 7568 7691 +3 7567 7348 7692 +3 516 7610 7667 +3 7407 7655 7691 +3 7657 7408 7692 +3 7655 7466 7691 +3 7465 7657 7692 +3 7597 7345 7700 +3 7425 7618 7701 +3 7618 7365 7701 +3 7464 7656 7700 + +CELL_TYPES 15576 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 + +CELL_DATA 15576 +SCALARS CellEntityIds int 1 +LOOKUP_TABLE default +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +7 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +4 +6 +6 +6 +6 +6 +6 +6 +6 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +11 +6 +6 +6 +6 +6 +6 +6 +6 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +2 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 +3 diff --git a/tests/ruff.toml b/tests/ruff.toml deleted file mode 100644 index 816bcd68ec..0000000000 --- a/tests/ruff.toml +++ /dev/null @@ -1,14 +0,0 @@ -# custom lint settings for testing - -extend = "../pyproject.toml" - -[lint] -extend-ignore = [ - "B015", # useless comparison - "B018", # useless expression - "E402", # module-level import not at top of file - "E731", # lambda assignment - "F841", # unused local variable - "S101", # asserts allowed in tests - "NPY201", # numpy 2.* compatibility check -] diff --git a/tests/sims/full_charge.h5 b/tests/sims/full_charge.h5 new file mode 100644 index 0000000000..3705abba66 Binary files /dev/null and b/tests/sims/full_charge.h5 differ diff --git a/tests/sims/full_charge.json b/tests/sims/full_charge.json new file mode 100644 index 0000000000..de5983fb17 --- /dev/null +++ b/tests/sims/full_charge.json @@ -0,0 +1,398 @@ +{ + "attrs": {}, + "type": "HeatChargeSimulation", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 3.0, + 3.0, + 0.0 + ], + "medium": { + "attrs": {}, + "name": "air", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + }, + "structures": [ + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.999, + 2.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "oxide", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "SolidMedium", + "capacity": 1.0, + "conductivity": 1.0, + "density": 1.0 + }, + "charge": null, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + -0.5, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "p_side", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "SemiconductorMedium", + "permittivity": 11.0, + "N_c": 2e+19, + "N_v": 2e+19, + "E_g": 1.0, + "mobility_n": { + "attrs": {}, + "mu": 1500.0, + "type": "ConstantMobilityModel" + }, + "mobility_p": { + "attrs": {}, + "mu_min": 44.9, + "mu": 470.5, + "exp_2": -2.33, + "exp_N": 0.719, + "ref_N": 2.23e+17, + "exp_1": -0.57, + "exp_3": 2.4, + "exp_4": -0.146, + "type": "CaugheyThomasMobility" + }, + "R": [ + { + "attrs": {}, + "tau_n": 3.3e-06, + "tau_p": 4e-06, + "type": "ShockleyReedHallRecombination" + }, + { + "attrs": {}, + "r_const": 1.6e-14, + "type": "RadiativeRecombination" + }, + { + "attrs": {}, + "c_n": 2.8e-31, + "c_p": 9.9e-32, + "type": "AugerRecombination" + } + ], + "delta_E_g": { + "attrs": {}, + "v1": 0.00692, + "n2": 1.3e+17, + "c2": 0.5, + "min_N": 1000000000000000.0, + "type": "SlotboomBandGapNarrowing" + }, + "N_a": 1e+18, + "N_d": 0.0 + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.5, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "n_side", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "SemiconductorMedium", + "permittivity": 11.0, + "N_c": 2e+19, + "N_v": 2e+19, + "E_g": 1.0, + "mobility_n": { + "attrs": {}, + "mu": 1500.0, + "type": "ConstantMobilityModel" + }, + "mobility_p": { + "attrs": {}, + "mu_min": 44.9, + "mu": 470.5, + "exp_2": -2.33, + "exp_N": 0.719, + "ref_N": 2.23e+17, + "exp_1": -0.57, + "exp_3": 2.4, + "exp_4": -0.146, + "type": "CaugheyThomasMobility" + }, + "R": [ + { + "attrs": {}, + "tau_n": 3.3e-06, + "tau_p": 4e-06, + "type": "ShockleyReedHallRecombination" + }, + { + "attrs": {}, + "r_const": 1.6e-14, + "type": "RadiativeRecombination" + }, + { + "attrs": {}, + "c_n": 2.8e-31, + "c_p": 9.9e-32, + "type": "AugerRecombination" + } + ], + "delta_E_g": { + "attrs": {}, + "v1": 0.00692, + "n2": 1.3e+17, + "c2": 0.5, + "min_N": 1000000000000000.0, + "type": "SlotboomBandGapNarrowing" + }, + "N_a": 0.0, + "N_d": 1e+18 + } + } + ], + "symmetry": [ + 0, + 0, + 0 + ], + "sources": [], + "boundary_spec": [ + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "p_side", + "air" + ] + }, + "condition": { + "attrs": {}, + "type": "VoltageBC", + "source": { + "attrs": {}, + "name": null, + "voltage": [ + -0.5, + 0.0, + 1.0 + ], + "units": "V", + "type": "DCVoltageSource" + } + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "n_side", + "air" + ] + }, + "condition": { + "attrs": {}, + "type": "VoltageBC", + "source": { + "attrs": {}, + "name": null, + "voltage": [ + 0.0 + ], + "units": "V", + "type": "DCVoltageSource" + } + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "oxide", + "air" + ] + }, + "condition": { + "attrs": {}, + "type": "InsulatingBC" + }, + "type": "HeatChargeBoundarySpec" + } + ], + "monitors": [ + { + "attrs": {}, + "type": "SteadyFreeCarrierMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "free_carrier_monitor", + "unstructured": true, + "conformal": false + }, + { + "attrs": {}, + "type": "SteadyPotentialMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "potential_monitor", + "unstructured": true, + "conformal": false + }, + { + "attrs": {}, + "type": "SteadyCapacitanceMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "capacitance_monitor", + "unstructured": true, + "conformal": false + } + ], + "grid_spec": { + "attrs": {}, + "relative_min_dl": 0.0, + "type": "UniformUnstructuredGrid", + "dl": 0.05, + "min_edges_per_circumference": 15.0, + "min_edges_per_side": 2.0, + "non_refined_structures": [] + }, + "version": "2.9.0rc2", + "plot_length_units": "\u03bcm", + "structure_priority_mode": "equal", + "analysis_spec": { + "attrs": {}, + "temperature": 300.0, + "tolerance_settings": { + "attrs": {}, + "abs_tol": 1000000.0, + "rel_tol": 0.0001, + "max_iters": 400, + "ramp_up_iters": 1, + "type": "ChargeToleranceSpec" + }, + "convergence_dv": 0.1, + "fermi_dirac": false, + "type": "IsothermalSteadyChargeDCAnalysis" + } +} \ No newline at end of file diff --git a/tests/sims/full_conduction.h5 b/tests/sims/full_conduction.h5 new file mode 100644 index 0000000000..062d17c4d9 Binary files /dev/null and b/tests/sims/full_conduction.h5 differ diff --git a/tests/sims/full_conduction.json b/tests/sims/full_conduction.json new file mode 100644 index 0000000000..95efc63923 --- /dev/null +++ b/tests/sims/full_conduction.json @@ -0,0 +1,284 @@ +{ + "attrs": {}, + "type": "HeatChargeSimulation", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 2.0, + 2.0, + 2.0 + ], + "medium": { + "attrs": {}, + "name": "air", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + }, + "structures": [ + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature0_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature0_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + -1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature1_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature1_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "solid_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "solid_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "SolidMedium", + "capacity": 1.0, + "conductivity": 1e-06, + "density": 1e-18 + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeConductorMedium", + "permittivity": 1.0, + "conductivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + } + ], + "symmetry": [ + 1, + 0, + 0 + ], + "sources": [], + "boundary_spec": [ + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature0_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "VoltageBC", + "source": { + "attrs": {}, + "name": null, + "voltage": [ + 5.0 + ], + "units": "V", + "type": "DCVoltageSource" + } + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature1_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "VoltageBC", + "source": { + "attrs": {}, + "name": null, + "voltage": [ + 0.0 + ], + "units": "V", + "type": "DCVoltageSource" + } + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "air", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "InsulatingBC" + }, + "type": "HeatChargeBoundarySpec" + } + ], + "monitors": [ + { + "attrs": {}, + "type": "SteadyPotentialMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "potential_monitor", + "unstructured": true, + "conformal": false + } + ], + "grid_spec": { + "attrs": {}, + "relative_min_dl": 0.001, + "type": "UniformUnstructuredGrid", + "dl": 0.05, + "min_edges_per_circumference": 15.0, + "min_edges_per_side": 2.0, + "non_refined_structures": [] + }, + "version": "2.9.0rc2", + "plot_length_units": "\u03bcm", + "structure_priority_mode": "equal", + "analysis_spec": null +} \ No newline at end of file diff --git a/tests/sims/simulation_sample.h5 b/tests/sims/full_fdtd.h5 similarity index 75% rename from tests/sims/simulation_sample.h5 rename to tests/sims/full_fdtd.h5 index c31ed926af..dc3c101119 100644 Binary files a/tests/sims/simulation_sample.h5 and b/tests/sims/full_fdtd.h5 differ diff --git a/tests/sims/simulation_sample.json b/tests/sims/full_fdtd.json similarity index 93% rename from tests/sims/simulation_sample.json rename to tests/sims/full_fdtd.json index 7abe00197f..3eb7cf135a 100644 --- a/tests/sims/simulation_sample.json +++ b/tests/sims/full_fdtd.json @@ -44,6 +44,7 @@ "name": "traced_dieletric_cylinder", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -78,6 +79,7 @@ "name": "traced_dieletric_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -124,6 +126,7 @@ "name": "traced custom polyslab", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -161,6 +164,7 @@ "name": "dieletric_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -195,6 +199,7 @@ "name": "lossy_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -225,6 +230,7 @@ "name": "sellmeier_sphere", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -267,6 +273,7 @@ "name": "lorentz_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -307,6 +314,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -341,6 +349,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -380,6 +389,7 @@ "name": "drude_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -419,6 +429,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -499,6 +510,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -553,6 +565,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -603,6 +616,76 @@ } } }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + -1.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": null, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "AnisotropicMedium", + "xx": { + "attrs": {}, + "name": "PMC", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "PMCMedium" + }, + "yy": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + }, + "zz": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 1.0, + "conductivity": 0.0 + } + } + }, { "attrs": {}, "geometry": { @@ -622,6 +705,7 @@ "name": "fully_anisotropic_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -694,6 +778,7 @@ "name": "pec_group", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -707,6 +792,39 @@ "type": "PECMedium" } }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + -1.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "PMC", + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "PMCMedium" + } + }, { "attrs": {}, "geometry": { @@ -726,6 +844,7 @@ "name": "anisotopic_cylinder", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -809,6 +928,7 @@ "name": "pole_slab", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -854,6 +974,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -891,6 +1012,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -932,6 +1054,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -974,6 +1097,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1015,6 +1139,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1056,6 +1181,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1096,6 +1222,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1139,6 +1266,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1198,6 +1326,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1264,6 +1393,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1323,6 +1453,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1382,6 +1513,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1434,6 +1566,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1473,6 +1606,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1555,6 +1689,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1595,6 +1730,7 @@ "name": "dieletric_mesh", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1639,6 +1775,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1692,6 +1829,7 @@ "name": "clip_operation", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1756,6 +1894,7 @@ "name": "transformed_box", "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -1770,6 +1909,59 @@ "permittivity": 1.5, "conductivity": 0.0 } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 1.0, + 1.0, + 1.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": null, + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "SiO2", + "optical": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "Medium", + "permittivity": 4.0, + "conductivity": 0.0 + }, + "heat": null, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 2.0 + }, + "type": "MultiPhysicsMedium" + } } ], "symmetry": [ @@ -1871,7 +2063,7 @@ "filter_pol": null, "angle_theta": 0.0, "angle_phi": 0.0, - "precision": "auto", + "precision": "double", "bend_radius": null, "bend_axis": null, "angle_rotation": false, @@ -1939,7 +2131,7 @@ "offset": 5.0, "remove_dc_component": true }, - "num_freqs": 3, + "num_freqs": 1, "direction": "+", "angle_theta": 0.0, "angle_phi": 0.0, @@ -1971,7 +2163,7 @@ "offset": 5.0, "remove_dc_component": true }, - "num_freqs": 3, + "num_freqs": 1, "direction": "+", "angle_theta": 0.0, "angle_phi": 0.0, @@ -2081,7 +2273,7 @@ "offset": 5.0, "remove_dc_component": true }, - "num_freqs": 3, + "num_freqs": 1, "direction": "+", "angle_theta": 0.5235987755982988, "angle_phi": 0.6283185307179586, @@ -2419,7 +2611,7 @@ "filter_pol": null, "angle_theta": 0.0, "angle_phi": 0.0, - "precision": "auto", + "precision": "double", "bend_radius": null, "bend_axis": null, "angle_rotation": false, @@ -3181,6 +3373,7 @@ "name": null, "background_permittivity": null, "background_medium": null, + "priority": null, "type": "Structure", "medium": { "attrs": {}, @@ -3201,8 +3394,9 @@ "layer_refinement_specs": [], "type": "GridSpec" }, - "version": "2.8.4", + "version": "2.9.0rc2", "plot_length_units": "\u03bcm", + "structure_priority_mode": "equal", "lumped_elements": [ { "attrs": {}, @@ -3273,6 +3467,7 @@ "simulation_type": "tidy3d", "post_norm": 1.0, "courant": 0.8, + "precision": "hybrid", "normalize_index": 0, "shutoff": 0.0001, "run_time": 1e-12 diff --git a/tests/sims/full_steady_heat.h5 b/tests/sims/full_steady_heat.h5 new file mode 100644 index 0000000000..4edda48971 Binary files /dev/null and b/tests/sims/full_steady_heat.h5 differ diff --git a/tests/sims/full_steady_heat.json b/tests/sims/full_steady_heat.json new file mode 100644 index 0000000000..7aebb96ef8 --- /dev/null +++ b/tests/sims/full_steady_heat.json @@ -0,0 +1,280 @@ +{ + "attrs": {}, + "type": "HeatChargeSimulation", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 2.0, + 2.0, + 2.0 + ], + "medium": { + "attrs": {}, + "name": "air", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + }, + "structures": [ + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature0_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature0_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + -1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature1_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature1_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "solid_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "solid_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "SolidMedium", + "capacity": 1.0, + "conductivity": 1e-06, + "density": 1e-18 + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeConductorMedium", + "permittivity": 1.0, + "conductivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + } + ], + "symmetry": [ + 1, + 0, + 0 + ], + "sources": [ + { + "attrs": {}, + "name": null, + "type": "HeatSource", + "structures": [ + "solid_box" + ], + "rate": 1.0 + } + ], + "boundary_spec": [ + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature0_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "TemperatureBC", + "temperature": 300.0 + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature1_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "TemperatureBC", + "temperature": 320.0 + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "air", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "HeatFluxBC", + "flux": 0.0 + }, + "type": "HeatChargeBoundarySpec" + } + ], + "monitors": [ + { + "attrs": {}, + "type": "TemperatureMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "temperature_monitor", + "unstructured": true, + "conformal": false, + "interval": 1 + } + ], + "grid_spec": { + "attrs": {}, + "relative_min_dl": 0.001, + "type": "UniformUnstructuredGrid", + "dl": 0.05, + "min_edges_per_circumference": 15.0, + "min_edges_per_side": 2.0, + "non_refined_structures": [] + }, + "version": "2.9.0rc2", + "plot_length_units": "\u03bcm", + "structure_priority_mode": "equal", + "analysis_spec": null +} \ No newline at end of file diff --git a/tests/sims/full_unsteady_heat.h5 b/tests/sims/full_unsteady_heat.h5 new file mode 100644 index 0000000000..1ca57cf8f2 Binary files /dev/null and b/tests/sims/full_unsteady_heat.h5 differ diff --git a/tests/sims/full_unsteady_heat.json b/tests/sims/full_unsteady_heat.json new file mode 100644 index 0000000000..3cd961955d --- /dev/null +++ b/tests/sims/full_unsteady_heat.json @@ -0,0 +1,290 @@ +{ + "attrs": {}, + "type": "HeatChargeSimulation", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 2.0, + 2.0, + 2.0 + ], + "medium": { + "attrs": {}, + "name": "air", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + }, + "structures": [ + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature0_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature0_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + -1.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "temperature1_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "temperature1_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "FluidMedium" + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeInsulatorMedium", + "permittivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + }, + { + "attrs": {}, + "geometry": { + "attrs": {}, + "type": "Box", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ] + }, + "name": "solid_box", + "background_permittivity": null, + "background_medium": null, + "priority": null, + "type": "Structure", + "medium": { + "attrs": {}, + "name": "solid_box", + "optical": null, + "heat": { + "attrs": {}, + "name": null, + "type": "SolidMedium", + "capacity": 1.0, + "conductivity": 1e-06, + "density": 1e-18 + }, + "charge": { + "attrs": {}, + "name": null, + "frequency_range": null, + "allow_gain": false, + "nonlinear_spec": null, + "modulation_spec": null, + "viz_spec": null, + "heat_spec": null, + "type": "ChargeConductorMedium", + "permittivity": 1.0, + "conductivity": 1.0 + }, + "type": "MultiPhysicsMedium" + } + } + ], + "symmetry": [ + 1, + 0, + 0 + ], + "sources": [ + { + "attrs": {}, + "name": null, + "type": "HeatSource", + "structures": [ + "solid_box" + ], + "rate": 1.0 + } + ], + "boundary_spec": [ + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature0_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "TemperatureBC", + "temperature": 300.0 + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "temperature1_box", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "TemperatureBC", + "temperature": 320.0 + }, + "type": "HeatChargeBoundarySpec" + }, + { + "attrs": {}, + "placement": { + "attrs": {}, + "type": "MediumMediumInterface", + "mediums": [ + "air", + "solid_box" + ] + }, + "condition": { + "attrs": {}, + "type": "HeatFluxBC", + "flux": 0.0 + }, + "type": "HeatChargeBoundarySpec" + } + ], + "monitors": [ + { + "attrs": {}, + "type": "TemperatureMonitor", + "center": [ + 0.0, + 0.0, + 0.0 + ], + "size": [ + 1.0, + 1.0, + 1.0 + ], + "name": "temperature_monitor", + "unstructured": true, + "conformal": false, + "interval": 1 + } + ], + "grid_spec": { + "attrs": {}, + "relative_min_dl": 0.001, + "type": "UniformUnstructuredGrid", + "dl": 0.05, + "min_edges_per_circumference": 15.0, + "min_edges_per_side": 2.0, + "non_refined_structures": [] + }, + "version": "2.9.0rc2", + "plot_length_units": "\u03bcm", + "structure_priority_mode": "equal", + "analysis_spec": { + "attrs": {}, + "initial_temperature": 300.0, + "unsteady_spec": { + "attrs": {}, + "time_step": 0.001, + "total_time_steps": 1000, + "type": "UnsteadySpec" + }, + "type": "UnsteadyHeatAnalysis" + } +} \ No newline at end of file diff --git a/tests/test_cli/full_test_develop.py b/tests/test_cli/full_test_develop.py index d46ca78a4d..7cf8e1d5f4 100644 --- a/tests/test_cli/full_test_develop.py +++ b/tests/test_cli/full_test_develop.py @@ -2,11 +2,14 @@ These scripts just test the CLI commands for the develop command, and verify that they run properly. """ +from __future__ import annotations + import os from unittest.mock import patch import pytest from click.testing import CliRunner + from tidy3d.web.cli import tidy3d_cli diff --git a/tests/test_components/material/test_multi_physics.py b/tests/test_components/material/test_multi_physics.py index 0641b00a70..6f3f8d90e4 100644 --- a/tests/test_components/material/test_multi_physics.py +++ b/tests/test_components/material/test_multi_physics.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import copy import pytest + import tidy3d as td @@ -14,6 +17,7 @@ def test_delegated_attributes_work(dummy_optical): # delegated names resolve assert mp.is_pec is dummy_optical.is_pec + assert mp.is_pmc is dummy_optical.is_pmc assert mp._eps_plot == dummy_optical._eps_plot assert mp.viz_spec == dummy_optical.viz_spec @@ -27,6 +31,9 @@ def test_delegated_attribute_without_optical_raises(): with pytest.raises(AttributeError, match=r"optical medium is 'None'"): _ = mp_no_opt.is_pec + with pytest.raises(AttributeError, match=r"optical medium is 'None'"): + _ = mp_no_opt.is_pmc + def test_has_cached_props(dummy_optical): mp = td.MultiPhysicsMedium(optical=dummy_optical) diff --git a/tests/test_components/test_IO.py b/tests/test_components/test_IO.py index b4fe3322df..83114f5678 100644 --- a/tests/test_components/test_IO.py +++ b/tests/test_components/test_IO.py @@ -1,5 +1,7 @@ """Tests file export and loading.""" +from __future__ import annotations + import json import os from time import time @@ -8,6 +10,7 @@ import h5py import numpy as np import pytest + import tidy3d as td from tidy3d import __version__ from tidy3d.components.base import DATA_ARRAY_MAP @@ -70,9 +73,9 @@ def test_simulation_load_export(split_string, tmp_path): SIM.to_hdf5(path_hdf5) SIM2 = td.Simulation.from_file(path) SIM_HDF5 = td.Simulation.from_hdf5(path_hdf5) - assert ( - set_datasets_to_none(SIM)._json_string == SIM2._json_string - ), "original and loaded simulations are not the same" + assert set_datasets_to_none(SIM)._json_string == SIM2._json_string, ( + "original and loaded simulations are not the same" + ) assert SIM == SIM_HDF5, "original and loaded from hdf5 simulations are not the same" @@ -80,9 +83,9 @@ def test_simulation_load_export_yaml(tmp_path): path = str(tmp_path / "simulation.yaml") SIM.to_file(path) SIM2 = td.Simulation.from_file(path) - assert ( - set_datasets_to_none(SIM)._json_string == SIM2._json_string - ), "original and loaded simulations are not the same" + assert set_datasets_to_none(SIM)._json_string == SIM2._json_string, ( + "original and loaded simulations are not the same" + ) def test_component_load_export(tmp_path): @@ -189,7 +192,7 @@ def test_validation_speed(tmp_path): for i in range(n): new_structure = SIM.structures[0].copy(update={"name": str(i)}) new_structures.append(new_structure) - S = SIM.copy(update=dict(structures=new_structures)) + S = SIM.copy(update={"structures": new_structures}) S.to_file(path) time_start = time() @@ -210,11 +213,14 @@ def test_validation_speed(tmp_path): @pytest.mark.parametrize("sim_file", SIM_FILES) def test_simulation_updater(sim_file): """Test that all simulations in ``SIM_DIR`` can be updated to current version and loaded.""" - sim_updated = td.Simulation.from_file(sim_file) - assert sim_updated.version == __version__, "Simulation not converted properly" + if "fdtd" in sim_file: + sim_loaded = td.Simulation.from_file(sim_file) + else: + sim_loaded = td.HeatChargeSimulation.from_file(sim_file) + assert sim_loaded.version == __version__, "Simulation not converted properly" # just make sure the loaded sim does something properly using this version - sim_updated.grid + assert sim_loaded.scene is not None def test_yaml(tmp_path): @@ -324,7 +330,7 @@ def test_monitor_data_from_file(): def test_data_array_to_hdf5(tmp_path): values = np.linspace(0, 1, 10) - coords = dict(f=values) + coords = {"f": values} flux = td.FluxDataArray(values, coords=coords) path = str(tmp_path / "flux.hdf5") diff --git a/tests/test_components/test_apodization.py b/tests/test_components/test_apodization.py index d1c3b14440..4fadd253d3 100644 --- a/tests/test_components/test_apodization.py +++ b/tests/test_components/test_apodization.py @@ -1,8 +1,11 @@ """Tests mode objects.""" +from __future__ import annotations + import matplotlib.pyplot as plt import pydantic.v1 as pydantic import pytest + import tidy3d as td diff --git a/tests/test_components/test_autograd.py b/tests/test_components/test_autograd.py index a4d582ced5..27ea536d2c 100644 --- a/tests/test_components/test_autograd.py +++ b/tests/test_components/test_autograd.py @@ -1,4 +1,5 @@ # test autograd integration into tidy3d +from __future__ import annotations import copy import cProfile @@ -13,17 +14,18 @@ import numpy as np import numpy.testing as npt import pytest -import tidy3d as td -import tidy3d.web as web import xarray as xr from autograd.test_util import check_grads + +import tidy3d as td +import tidy3d.web as web +from tidy3d.components.autograd.constants import MAX_NUM_TRACED_STRUCTURES from tidy3d.components.autograd.derivative_utils import DerivativeInfo from tidy3d.components.autograd.utils import is_tidy_box from tidy3d.components.data.data_array import DataArray from tidy3d.exceptions import AdjointError from tidy3d.plugins.polyslab import ComplexPolySlab from tidy3d.web import run, run_async -from tidy3d.web.api.autograd.autograd import MAX_NUM_TRACED_STRUCTURES from tidy3d.web.api.autograd.utils import FieldMap from ..utils import SIM_FULL, AssertLogLevel, run_emulated, tracer_arr @@ -86,7 +88,7 @@ PML_X = True if IS_3D else False # shape of the custom medium -DA_SHAPE_X = 1 if IS_3D else 1 +DA_SHAPE_X = 1 DA_SHAPE = (DA_SHAPE_X, 1_000, 1_000) if TEST_CUSTOM_MEDIUM_SPEED else (DA_SHAPE_X, 12, 12) # number of vertices in the polyslab @@ -175,7 +177,7 @@ def emulated_run_fwd(simulation, task_name, **run_kwargs) -> td.SimulationData: sim_original = simulation sim_fields_keys = run_kwargs["sim_fields_keys"] # add gradient monitors and make combined simulation - sim_combined = sim_original.with_adjoint_monitors(sim_fields_keys) + sim_combined = sim_original._with_adjoint_monitors(sim_fields_keys) sim_data_combined = run_emulated(sim_combined, task_name=task_name) # store both original and fwd data aux_data @@ -235,7 +237,7 @@ class EmulatedBatchData(web.BatchData): def load_sim_data(self, task_name): return batch_data_orig[task_name] - task_paths = {task_name: "" for task_name in simulations.keys()} + task_paths = dict.fromkeys(simulations.keys(), "") batch_data = EmulatedBatchData( task_paths=task_paths, @@ -319,11 +321,11 @@ def make_structures(params: anp.ndarray) -> dict[str, td.Structure]: medium=td.CustomMedium( permittivity=td.SpatialDataArray( eps_arr, - coords=dict( - x=np.linspace(-0.5, 0.5, nx), - y=np.linspace(-0.5, 0.5, ny), - z=np.linspace(-0.5, 0.5, nz), - ), + coords={ + "x": np.linspace(-0.5, 0.5, nx), + "y": np.linspace(-0.5, 0.5, ny), + "z": np.linspace(-0.5, 0.5, nz), + }, ), ), ) @@ -331,12 +333,12 @@ def make_structures(params: anp.ndarray) -> dict[str, td.Structure]: # custom medium with vector valued permittivity data eps_ii = td.ScalarFieldDataArray( eps_arr.reshape(nx, ny, nz, 1), - coords=dict( - x=np.linspace(-0.5, 0.5, nx), - y=np.linspace(-0.5, 0.5, ny), - z=np.linspace(-0.5, 0.5, nz), - f=[td.C_0], - ), + coords={ + "x": np.linspace(-0.5, 0.5, nx), + "y": np.linspace(-0.5, 0.5, ny), + "z": np.linspace(-0.5, 0.5, nz), + "f": [td.C_0], + }, ) custom_med_vec = td.Structure( @@ -452,7 +454,7 @@ def make_structures(params: anp.ndarray) -> dict[str, td.Structure]: x = np.linspace(-0.5, 0.5, nx) y = np.linspace(-0.5, 0.5, ny) z = np.linspace(-0.5, 0.5, nz) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} eps_inf = td.SpatialDataArray(anp.real(custom_disp_values), coords=coords) a1 = td.SpatialDataArray(-custom_disp_values, coords=coords) @@ -473,20 +475,20 @@ def make_structures(params: anp.ndarray) -> dict[str, td.Structure]: ) cylinder = td.Structure(geometry=cylinder_geo, medium=polyslab.medium) - return dict( - medium=medium, - center_list=center_list, - size_element=size_element, - custom_med=custom_med, - custom_med_vec=custom_med_vec, - polyslab=polyslab, - polyslab_dispersive=polyslab_dispersive, - geo_group=geo_group, - complex_polyslab=complex_polyslab_geo_group, - pole_res=pole_res, - custom_pole_res=custom_pole_res, - cylinder=cylinder, - ) + return { + "medium": medium, + "center_list": center_list, + "size_element": size_element, + "custom_med": custom_med, + "custom_med_vec": custom_med_vec, + "polyslab": polyslab, + "polyslab_dispersive": polyslab_dispersive, + "geo_group": geo_group, + "complex_polyslab": complex_polyslab_geo_group, + "pole_res": pole_res, + "custom_pole_res": custom_pole_res, + "cylinder": cylinder, + } def make_monitors() -> dict[str, tuple[td.Monitor, typing.Callable[[td.SimulationData], float]]]: @@ -547,12 +549,12 @@ def field_point_postprocess_fn(sim_data, mnt_data): value += anp.sum(sim_data.get_intensity(mnt_data.monitor.name).values) return value - return dict( - mode=(mode_mnt, mode_postprocess_fn), - diff=(diff_mnt, diff_postprocess_fn), - field_vol=(field_vol, field_vol_postprocess_fn), - field_point=(field_point, field_point_postprocess_fn), - ) + return { + "mode": (mode_mnt, mode_postprocess_fn), + "diff": (diff_mnt, diff_postprocess_fn), + "field_vol": (field_vol, field_vol_postprocess_fn), + "field_point": (field_point, field_point_postprocess_fn), + } def plot_sim(sim: td.Simulation, plot_eps: bool = True) -> None: @@ -646,7 +648,7 @@ def postprocess(data: td.SimulationData) -> float: mnt_data = data[monitor_key] return monitor_pp_fn(data, mnt_data) - return dict(sim=make_sim, postprocess=postprocess) + return {"sim": make_sim, "postprocess": postprocess} @pytest.mark.parametrize("axis", (0, 1, 2)) @@ -810,7 +812,7 @@ def test_autograd_async(use_emulated_run, structure_key, monitor_key): make_sim = fn_dict["sim"] postprocess = fn_dict["postprocess"] - task_names = {"test_a", "adjoint", "task1", "_test"} + task_names = {"test_a", "adjoint", "_test"} def objective(*args): sims = {task_name: make_sim(*args) for task_name in task_names} @@ -910,7 +912,7 @@ def test_autograd_async_some_zero_grad(use_emulated_run, structure_key, monitor_ make_sim = fn_dict["sim"] postprocess = fn_dict["postprocess"] - task_names = {"1", "2", "3", "4"} + task_names = {"1", "2"} def objective(*args): sims = {task_name: make_sim(*args) for task_name in task_names} @@ -932,7 +934,7 @@ def test_autograd_async_all_zero_grad(use_emulated_run): make_sim = fn_dict["sim"] postprocess = fn_dict["postprocess"] - task_names = {"1", "2", "3", "4"} + task_names = {"1", "2"} def objective(*args): sims = {task_name: make_sim(*args) for task_name in task_names} @@ -1095,16 +1097,16 @@ def test_sim_full_ops(structure_key): def objective(*params): s = make_structures(*params)[structure_key] s = s.updated_copy(geometry=s.geometry.updated_copy(center=(2, 2, 2), size=(0, 0, 0))) - sim_full_traced = SIM_FULL.updated_copy(structures=list(SIM_FULL.structures) + [s]) + sim_full_traced = SIM_FULL.updated_copy(structures=[*list(SIM_FULL.structures), s]) sim_full_static = sim_full_traced.to_static() - sim_fields = sim_full_traced.strip_traced_fields() + sim_fields = sim_full_traced._strip_traced_fields() # note: there is one traced structure in SIM_FULL already with 6 fields + 1 = 7 assert len(sim_fields) == 10 - sim_traced = sim_full_static.insert_traced_fields(sim_fields) + sim_traced = sim_full_static._insert_traced_fields(sim_fields) assert sim_traced == sim_full_traced @@ -1134,8 +1136,8 @@ def test_sim_fields_io(structure_key, tmp_path): from file, and then converting back, returns the same object.""" s = make_structures(params0)[structure_key] s = s.updated_copy(geometry=s.geometry.updated_copy(center=(2, 2, 2), size=(0, 0, 0))) - sim_full_traced = SIM_FULL.updated_copy(structures=list(SIM_FULL.structures) + [s]) - sim_fields = sim_full_traced.strip_traced_fields() + sim_full_traced = SIM_FULL.updated_copy(structures=[*list(SIM_FULL.structures), s]) + sim_fields = sim_full_traced._strip_traced_fields() field_map = FieldMap.from_autograd_field_map(sim_fields) field_map_file = join(tmp_path, "test_sim_fields.hdf5.gz") @@ -1150,7 +1152,7 @@ def test_web_incompatible_inputs(monkeypatch): def catch(*args, **kwargs): """Just raise an exception.""" - raise AssertionError() + raise AssertionError monkeypatch.setattr(td.web.api.webapi, "run", catch) monkeypatch.setattr(td.web.api.container.Job, "run", catch) @@ -1225,6 +1227,147 @@ def objective(args): ag.grad(objective)(params0) +def test_adjoint_src_width(): + """Test the adjoint source width for single sources decays by f=0.""" + + f0 = td.C_0 / 1.55 + fwidth = f0 + + fwidths = f0 * np.linspace(0.1, 1.0, 5) + + adj_srcs = [ + td.PointDipole( + center=(0, 0, 0), + source_time=td.GaussianPulse(freq0=f0, fwidth=fwidth), + polarization="Ex", + ) + for fwidth in fwidths + ] + + adj_srcs_fwidth = td.SimulationData._adjoint_src_width_single(adj_srcs) + + for src in adj_srcs_fwidth: + assert np.isclose((src.source_time.freq0 - f0) / f0, 0.0), ( + "f0 of adjoint source should be centered on original f0" + ) + + check_fwidth = ( + src.source_time.freq0 + - td.components.data.sim_data.NUM_ADJOINT_FWIDTH_TO_ZERO * src.source_time.fwidth + ) / src.source_time.freq0 + + assert np.isclose(check_fwidth, 0.0) or (check_fwidth > 0.0), ( + "fwidth of adjoint source should decay sufficiently before f=0" + ) + + +def test_broadband_adjoint_src_width(): + """Test the broadband adjoint source handling for choosing fwidth.""" + + # Test the case where we have a custom current source and a wide adjoint source width that overlaps with zero. + # In this case, we want to issue a warning to the user about the adjoint accuracy of this setup. + f0_high = td.C_0 / 1.55 + f0_low = 0.1 * f0_high + + f0_adj_all = [f0_low, f0_high] + + fwidth = 0.1 * f0_high + + adj_srcs = [] + x = np.array([0.0]) + y = np.array([0.0]) + z = np.array([0.0]) + for f0 in f0_adj_all: + f = np.array([f0]) + + coords = {"x": x, "y": y, "z": z, "f": f} + + dataset = td.FieldDataset(Ex=td.ScalarFieldDataArray(np.ones((1, 1, 1, 1)), coords=coords)) + + adj_srcs.append( + td.CustomCurrentSource( + center=(0, 0, 0), + size=(0, 0, 0), + source_time=td.GaussianPulse(freq0=f0, fwidth=fwidth), + current_dataset=dataset, + ) + ) + + EXPECTED_WARNING_MSG_PIECE = ( + "Adjoint source generated with a frequency spectrum that extends to or overlaps with 0 Hz" + ) + with AssertLogLevel("WARNING", contains_str=EXPECTED_WARNING_MSG_PIECE): + broadband_f0, broadband_fwidth = td.SimulationData._adjoint_src_width_broadband(adj_srcs) + + f0_expected = 0.5 * (np.max(f0_adj_all) + np.min(f0_adj_all)) + + fwidth_expected = ( + f0_expected - np.min(f0_adj_all) + ) / td.components.data.sim_data.NUM_ADJOINT_FWIDTH_TO_FMIN + + assert np.isclose((f0_expected - broadband_f0) / f0_expected, 0.0), ( + "Expected freq0 not matching for broadband source" + ) + assert np.isclose((fwidth_expected - broadband_fwidth) / fwidth_expected, 0.0), ( + "Expected fwidth not matching for broadband source" + ) + + # Test the case where we need a wider pulse to cover all the adjoint frequencies than we would otherwise choose for + # each individual adjoint source + f0_broadband = np.linspace(f0_low, f0_high, 10) + fwidth_broadband = 0.1 * np.mean(f0_broadband) + + adj_srcs = [ + td.PointDipole( + center=(0, 0, 0), + source_time=td.GaussianPulse(freq0=f0, fwidth=fwidth_broadband), + polarization="Ex", + ) + for f0 in f0_broadband + ] + + broadband_f0, broadband_fwidth = td.SimulationData._adjoint_src_width_broadband(adj_srcs) + + f0_expected = 0.5 * (np.max(f0_broadband) + np.min(f0_broadband)) + fwidth_expected = ( + f0_expected - np.min(f0_broadband) + ) / td.components.data.sim_data.NUM_ADJOINT_FWIDTH_TO_FMIN + + assert np.isclose((f0_expected - broadband_f0) / f0_expected, 0.0), ( + "Expected freq0 not matching for broadband source" + ) + assert np.isclose((fwidth_expected - broadband_fwidth) / fwidth_expected, 0.0), ( + "Expected fwidth not matching for broadband source" + ) + + # Test the case where we have a narrow set of frequencies for the adjoint sources and so we can + # choose a wider overall source than is needed for covering those frequencies. This larger pulse width + # in frequency will shorten the time pulse. + f0_broadband = np.linspace(0.95 * f0_high, 1.05 * f0_high, 10) + fwidth_broadband = 0.1 * np.mean(f0_broadband) + + adj_srcs = [ + td.PointDipole( + center=(0, 0, 0), + source_time=td.GaussianPulse(freq0=f0, fwidth=fwidth_broadband), + polarization="Ex", + ) + for f0 in f0_broadband + ] + + broadband_f0, broadband_fwidth = td.SimulationData._adjoint_src_width_broadband(adj_srcs) + + f0_expected = 0.5 * (np.max(f0_broadband) + np.min(f0_broadband)) + fwidth_expected = f0_expected / td.components.data.sim_data.NUM_ADJOINT_FWIDTH_TO_ZERO + + assert np.isclose((f0_expected - broadband_f0) / f0_expected, 0.0), ( + "Expected freq0 not matching for broadband source" + ) + assert np.isclose((fwidth_expected - broadband_fwidth) / fwidth_expected, 0.0), ( + "Expected fwidth not matching for broadband source" + ) + + @pytest.mark.parametrize("colocate", [True, False]) @pytest.mark.parametrize("objtype", ["flux", "intensity"]) def test_interp_objectives(use_emulated_run, colocate, objtype): @@ -1434,7 +1577,7 @@ def J(eps): monkeypatch.setattr( td.PoleResidue, - "derivative_eps_complex_volume", + "_derivative_eps_complex_volume", lambda self, E_der_map, bounds, freqs: dJ_deps, ) @@ -1462,12 +1605,12 @@ def J(eps): eps_out=1.0, frequency=freq, bounds=((-1, -1, -1), (1, 1, 1)), - eps_no_structure=td.SpatialDataArray([[[1.0]]], coords=dict(x=[0], y=[0], z=[0])), - eps_inf_structure=td.SpatialDataArray([[[2.0]]], coords=dict(x=[0], y=[0], z=[0])), + eps_no_structure=td.SpatialDataArray([[[1.0]]], coords={"x": [0], "y": [0], "z": [0]}), + eps_inf_structure=td.SpatialDataArray([[[2.0]]], coords={"x": [0], "y": [0], "z": [0]}), bounds_intersect=((-1, -1, -1), (1, 1, 1)), ) - grads_computed = pr.compute_derivatives(derivative_info=info) + grads_computed = pr._compute_derivatives(derivative_info=info) def f(eps_inf, poles): eps = td.PoleResidue._eps_model(eps_inf, poles, freq) @@ -1496,7 +1639,7 @@ def test_custom_pole_residue(monkeypatch): x = np.linspace(-0.5, 0.5, nx) y = np.linspace(-0.5, 0.5, ny) z = np.linspace(-0.5, 0.5, nz) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} eps_inf = td.SpatialDataArray(anp.real(values), coords=coords) a1 = td.SpatialDataArray(-values, coords=coords) @@ -1507,18 +1650,18 @@ def test_custom_pole_residue(monkeypatch): custom_med_pole_res = td.CustomPoleResidue(eps_inf=eps_inf, poles=poles) def J(eps): - return anp.sum(abs(eps)) + return anp.sum(anp.abs(eps)) freq = 3e8 pr = td.CustomPoleResidue(eps_inf=eps_inf, poles=poles) eps0 = pr.eps_model(freq) - dJ_deps = ag.holomorphic_grad(J)(eps0) + dJ_deps = np.conj(ag.holomorphic_grad(J)(eps0)) monkeypatch.setattr( td.CustomPoleResidue, "_derivative_field_cmp", - lambda self, E_der_map, eps_data, dim, freqs: dJ_deps, + lambda self, E_der_map, eps_data, dim, freqs: dJ_deps / 3.0, ) import importlib @@ -1544,12 +1687,12 @@ def J(eps): eps_out=1.0, frequency=freq, bounds=((-1, -1, -1), (1, 1, 1)), - eps_no_structure=td.SpatialDataArray([[[1.0]]], coords=dict(x=[0], y=[0], z=[0])), - eps_inf_structure=td.SpatialDataArray([[[2.0]]], coords=dict(x=[0], y=[0], z=[0])), + eps_no_structure=td.SpatialDataArray([[[1.0]]], coords={"x": [0], "y": [0], "z": [0]}), + eps_inf_structure=td.SpatialDataArray([[[2.0]]], coords={"x": [0], "y": [0], "z": [0]}), bounds_intersect=((-1, -1, -1), (1, 1, 1)), ) - grads_computed = pr.compute_derivatives(derivative_info=info) + grads_computed = pr._compute_derivatives(derivative_info=info) poles_complex = [ (np.array(a.values, dtype=complex), np.array(c.values, dtype=complex)) for a, c in poles @@ -1560,17 +1703,18 @@ def f(eps_inf, poles): eps = td.CustomPoleResidue._eps_model(eps_inf, poles, freq) return J(eps) - gfn = ag.holomorphic_grad(f, argnum=(0, 1)) - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - grad_eps_inf, grad_poles = gfn(eps_inf.values, poles_complex) + gfn = ag.grad(lambda x: f(x, poles_complex)) + grad_eps_inf = gfn(eps_inf.values) assert np.allclose(grads_computed[("eps_inf",)], grad_eps_inf) + gfn = ag.holomorphic_grad(lambda x: f(eps_inf.values, x)) + grad_poles = gfn(poles_complex) + for i in range(len(poles)): for j in range(2): field_path = ("poles", i, j) - assert np.allclose(grads_computed[field_path], grad_poles[i][j]) + assert np.allclose(grads_computed[field_path], np.conj(grad_poles[i][j])) # @pytest.mark.timeout(18.0) @@ -1661,7 +1805,7 @@ def objective(params): structure_traced = make_structures(params)[structure_key] sim = SIM_BASE.updated_copy( structures=[structure_traced], - monitors=list(SIM_BASE.monitors) + [mnt_single, mnt_multi], + monitors=[*list(SIM_BASE.monitors), mnt_single, mnt_multi], ) data = run(sim, task_name="multifreq_test") return postprocess_fn(data) @@ -1764,16 +1908,16 @@ def postprocess(sim_data: td.SimulationData) -> float: return postprocess -MULT_FREQ_TEST_CASES = dict( - src_1_freq_1=check_1_src_single, - src_2_freq_1=check_2_src_single, - src_1_freq_2=check_1_src_multi, - src_2_freq_1_mon_1=check_1_src_multi, - src_2_freq_1_mon_2=check_2_src_both, - src_2_freq_2_mon_1=check_1_multisrc, - src_2_freq_2_mon_2=check_2_multisrc, - src_1_freq_2_broadband=check_1_src_broadband, -) +MULT_FREQ_TEST_CASES = { + "src_1_freq_1": check_1_src_single, + "src_2_freq_1": check_2_src_single, + "src_1_freq_2": check_1_src_multi, + "src_2_freq_1_mon_1": check_1_src_multi, + "src_2_freq_1_mon_2": check_2_src_both, + "src_2_freq_2_mon_1": check_1_multisrc, + "src_2_freq_2_mon_2": check_2_multisrc, + "src_1_freq_2_broadband": check_1_src_broadband, +} checks = list(MULT_FREQ_TEST_CASES.items()) @@ -1783,18 +1927,13 @@ def postprocess(sim_data: td.SimulationData) -> float: def test_multi_freq_edge_cases(use_emulated_run, structure_key, label, check_fn, monkeypatch): # test multi-frequency adjoint handling - import tidy3d.components.data.sim_data as sd - - monkeypatch.setattr(sd, "RESIDUAL_CUTOFF_ADJOINT", 1) - reload(td) - postprocess_fn = check_fn(structure_key=structure_key) def objective(params): structure_traced = make_structures(params)[structure_key] sim = SIM_BASE.updated_copy( structures=[structure_traced], - monitors=list(SIM_BASE.monitors) + [mnt_single, mnt_multi], + monitors=[*list(SIM_BASE.monitors), mnt_single, mnt_multi], ) data = run(sim, task_name="multifreq_test") return postprocess_fn(data) @@ -1818,7 +1957,7 @@ def objective_indi(params, structure_key) -> float: structure_traced = make_structures(params)[structure_key] sim = SIM_BASE.updated_copy( structures=[structure_traced], - monitors=list(SIM_BASE.monitors) + [mnt_multi], + monitors=[*list(SIM_BASE.monitors), mnt_multi], ) sim_data = web.run(sim, task_name="multifreq_test") @@ -1832,7 +1971,7 @@ def objective_multi(params, structure_key) -> float: structure_traced = make_structures(params)[structure_key] sim = SIM_BASE.updated_copy( structures=[structure_traced], - monitors=list(SIM_BASE.monitors) + [mnt_multi], + monitors=[*list(SIM_BASE.monitors), mnt_multi], ) sim_data = web.run(sim, task_name="multifreq_test") amps = get_amps(sim_data, "multi").sel(mode_index=0, direction="+") @@ -2141,7 +2280,7 @@ def objective(params): structure_traced = make_structures(params)["medium"] sim = SIM_BASE.updated_copy(structures=[structure_traced], monitors=monitors) data = run(sim, task_name="adjoint_freq_test") - assert data.simulation.freqs_adjoint == [FREQ0] + assert data.simulation._freqs_adjoint == [FREQ0] return anp.sum(data["field"].flux.values) return objective @@ -2182,10 +2321,16 @@ def objective(center, size): sim_data = run_emulated(sim, task_name="adjoint_test") return postprocess(sim_data) - with AssertLogLevel("WARNING", contains_str="autograd tracer"): + with ( + AssertLogLevel("WARNING", contains_str="autograd tracer"), + pytest.warns(UserWarning, match="Output seems independent of input."), + ): grad = ag.grad(objective, argnum=0)(base_sim.center, base_sim.size) - with AssertLogLevel("WARNING", contains_str="autograd tracer"): + with ( + AssertLogLevel("WARNING", contains_str="autograd tracer"), + pytest.warns(UserWarning, match="Output seems independent of input."), + ): grad = ag.grad(objective, argnum=1)(base_sim.center, base_sim.size) diff --git a/tests/test_components/test_autograd_mode_polyslab_numerical.py b/tests/test_components/test_autograd_mode_polyslab_numerical.py index 3c2540aa51..a5224dbf79 100644 --- a/tests/test_components/test_autograd_mode_polyslab_numerical.py +++ b/tests/test_components/test_autograd_mode_polyslab_numerical.py @@ -1,4 +1,5 @@ # test autograd and compares to numerically computed finite difference gradients +from __future__ import annotations import operator import sys @@ -7,9 +8,10 @@ import matplotlib.pylab as plt import numpy as np import pytest +from scipy.ndimage import gaussian_filter + import tidy3d as td import tidy3d.web as web -from scipy.ndimage import gaussian_filter PLOT_FD_ADJ_COMPARISON = False NUM_FINITE_DIFFERENCE = 10 @@ -167,7 +169,7 @@ def make_base_sim( monitor_index_block = td.Box( center=(0, 0, 0.25 * sim_size_um[2] + mesh_wvl_um), - size=tuple(2 * size for size in sim_size_um[0:2]) + (mesh_wvl_um + 0.5 * sim_size_um[2],), + size=(*tuple(2 * size for size in sim_size_um[0:2]), mesh_wvl_um + 0.5 * sim_size_um[2]), ) sim_base = td.Simulation( @@ -204,7 +206,7 @@ def objective(vertices): sim_base = create_sim_base() simulation_dict = {} - for idx in range(0, len(vertices)): + for idx in range(len(vertices)): vertices_x = vertices[idx][0:NUM_VERTICES] vertices_y = vertices[idx][NUM_VERTICES:] @@ -232,7 +234,7 @@ def objective(vertices): ) sim_with_polyslab = sim_base.updated_copy( - structures=sim_base.structures + (polyslab_structure,) + structures=(*sim_base.structures, polyslab_structure) ) simulation_dict[f"numerical_mode_polyslab_testing_{idx}"] = sim_with_polyslab.copy() @@ -242,7 +244,7 @@ def objective(vertices): ) objective_vals = [] - for idx in range(0, len(vertices)): + for idx in range(len(vertices)): objective_vals.append(eval_fn(sim_data[f"numerical_mode_polyslab_testing_{idx}"])) if len(vertices) == 1: @@ -277,7 +279,7 @@ def objective(vertices): mode_data_test_parameters = [] test_number = 0 -for idx in range(0, len(mesh_wvls_um)): +for idx in range(len(mesh_wvls_um)): mesh_wvl_um = mesh_wvls_um[idx] adj_wvl_um = adj_wvls_um[idx] @@ -346,7 +348,7 @@ def test_finite_difference_mode_data_polyslab( box_for_override = td.Box( center=(0, 0, 0), - size=(np.inf, np.inf) + (MODE_LAYER_HEIGHT_WVL * mesh_wvl_um + mesh_wvl_um,), + size=(np.inf, np.inf, MODE_LAYER_HEIGHT_WVL * mesh_wvl_um + mesh_wvl_um), ) sim_path_dir = tmp_path / f"test{test_number}" @@ -405,7 +407,7 @@ def eval_fn(sim_data): obj, adj_grad = obj_val_and_grad([list(vertex_centers_x) + list(vertex_centers_y)]) - for fd_idx in range(0, NUM_FINITE_DIFFERENCE): + for fd_idx in range(NUM_FINITE_DIFFERENCE): # Create random perturbation of vertices to check against the computed adjoint gradient. random_pattern = rng.random(2 * NUM_VERTICES) - 0.5 random_pattern = gaussian_filter(random_pattern, sigma=1) @@ -425,7 +427,7 @@ def eval_fn(sim_data): all_obj = objective(all_vertex) fd_grad = np.zeros(NUM_FINITE_DIFFERENCE) - for fd_idx in range(0, NUM_FINITE_DIFFERENCE): + for fd_idx in range(NUM_FINITE_DIFFERENCE): obj_up_location = 2 * fd_idx obj_down_location = 2 * fd_idx + 1 diff --git a/tests/test_components/test_autograd_numerical.py b/tests/test_components/test_autograd_numerical.py index 3f1e827038..6def75ec10 100644 --- a/tests/test_components/test_autograd_numerical.py +++ b/tests/test_components/test_autograd_numerical.py @@ -1,4 +1,5 @@ # test autograd and compares to numerically computed finite difference gradients +from __future__ import annotations import operator import sys @@ -7,9 +8,10 @@ import matplotlib.pylab as plt import numpy as np import pytest +from scipy.ndimage import gaussian_filter + import tidy3d as td import tidy3d.web as web -from scipy.ndimage import gaussian_filter PLOT_FD_ADJ_COMPARISON = False NUM_FINITE_DIFFERENCE = 10 @@ -95,7 +97,7 @@ def make_base_sim( monitor_index_block = td.Box( center=(0, 0, 0.25 * sim_size_um[2] + mesh_wvl_um), - size=tuple(2 * size for size in sim_size_um[0:2]) + (mesh_wvl_um + 0.5 * sim_size_um[2],), + size=(*tuple(2 * size for size in sim_size_um[0:2]), mesh_wvl_um + 0.5 * sim_size_um[2]), ) monitor_index_block_structure = td.Structure( geometry=monitor_index_block, medium=td.Medium(permittivity=monitor_bg_index**2) @@ -125,14 +127,14 @@ def objective(perm_arrays): sim_base = create_sim_base() simulation_dict = {} - for idx in range(0, len(perm_arrays)): + for idx in range(len(perm_arrays)): block_structure = td.Structure.from_permittivity_array( eps_data=perm_arrays[idx], geometry=geometry, ) sim_with_block = sim_base.updated_copy( - structures=sim_base.structures + (block_structure,) + structures=(*sim_base.structures, block_structure) ) simulation_dict[f"numerical_field_testing_{idx}"] = sim_with_block.copy() @@ -142,7 +144,7 @@ def objective(perm_arrays): ) objective_vals = [] - for idx in range(0, len(perm_arrays)): + for idx in range(len(perm_arrays)): objective_vals.append(eval_fn(sim_data[f"numerical_field_testing_{idx}"])) if len(perm_arrays) == 1: @@ -191,7 +193,7 @@ def flux(sim_data): field_data_test_parameters = [] test_number = 0 -for idx in range(0, len(mesh_wvls_um)): +for idx in range(len(mesh_wvls_um)): mesh_wvl_um = mesh_wvls_um[idx] adj_wvl_um = adj_wvls_um[idx] @@ -305,7 +307,7 @@ def test_finite_difference_field_data(field_data_test_parameters, rng, tmp_path, all_perm = [] pattern_dot_adj_gradient = np.zeros(NUM_FINITE_DIFFERENCE) - for fd_idx in range(0, NUM_FINITE_DIFFERENCE): + for fd_idx in range(NUM_FINITE_DIFFERENCE): random_pattern = rng.random((dim, dim, Nz)) - 0.5 random_pattern = gaussian_filter(random_pattern, sigma=3) random_pattern /= np.linalg.norm(random_pattern) @@ -321,7 +323,7 @@ def test_finite_difference_field_data(field_data_test_parameters, rng, tmp_path, all_obj = objective(all_perm) fd_grad = np.zeros(NUM_FINITE_DIFFERENCE) - for fd_idx in range(0, NUM_FINITE_DIFFERENCE): + for fd_idx in range(NUM_FINITE_DIFFERENCE): obj_up_location = 2 * fd_idx obj_down_location = 2 * fd_idx + 1 diff --git a/tests/test_components/test_autograd_polyslab.py b/tests/test_components/test_autograd_polyslab.py new file mode 100644 index 0000000000..93c3542302 --- /dev/null +++ b/tests/test_components/test_autograd_polyslab.py @@ -0,0 +1,852 @@ +""" +Tests for ``td.PolySlab._compute_derivatives`` using an integrand of the form + + k(u, v, w) = a u + b v + c w + d + +where (u, v) are the in-plane coordinates and w is the extrusion axis. + +Test coverage: + - 3d slabs for each extrusion axis (0, 1, 2) + - 2d simulation slice (``is_2d``) where the slab is entirely in-plane + - 2d cross-section where the slab is intersected by a clipping plane +""" + +from __future__ import annotations + +from typing import Optional + +import numpy as np +import numpy.testing as npt +import pytest +import shapely.geometry as sgeom +from shapely.geometry.polygon import orient + +import tidy3d as td +from tidy3d.components.autograd.derivative_utils import DerivativeInfo + +# irregular convex pentagon in the XY-plane +VERTS_2D: np.ndarray = np.array( + [ + (0.0, 0.0), + (3.0, 0.0), + (4.0, 2.0), + (2.0, 4.0), + (0.0, 3.0), + ], + dtype=float, +) + +# slab bounds along the extrusion axis (z-min, z-max) +SLAB_BOUNDS: tuple[float, float] = (0.5, 2.0) + +a, b, c, d = 0.3, -0.1, 0.5, 0.8 +COEFFS: dict[str, float] = {"a": a, "b": b, "c": c, "d": d} + + +def polygon_area_centroid(verts: np.ndarray) -> tuple[float, float, float]: + """Return (area, x dA, y dA) for a CCW polygon (shoelace formulas)""" + x, y = verts.T + x1, y1 = np.roll(x, -1), np.roll(y, -1) + cross = x * y1 - y * x1 + area = 0.5 * np.sum(cross) + mx = np.sum((x + x1) * cross) / 6 + my = np.sum((y + y1) * cross) / 6 + return abs(area), mx, my + + +def edge_integrals(verts: np.ndarray): + """Per-edge geometric quantities""" + v0 = verts + v1 = np.roll(verts, -1, axis=0) + seg = v1 - v0 + + L = np.linalg.norm(seg, axis=1) # segment length + n = np.stack([seg[:, 1], -seg[:, 0]], axis=1) / L[:, None] # outward normal + + int_x = 0.5 * (v0[:, 0] + v1[:, 0]) * L # x ds per segment + int_y = 0.5 * (v0[:, 1] + v1[:, 1]) * L # y ds per segment + + return L, n, int_x, int_y + + +def get_edge_intersection(v0, v1, x_clip): + """Find intersection of edge (v0, v1) with line x=x_clip.""" + x0, y0 = v0 + x1, y1 = v1 + if np.isclose(x0, x1): # vertical edge + return None, None + if (x0 <= x_clip and x1 <= x_clip) or (x0 > x_clip and x1 > x_clip): # edge doesn't cross + return None, None + + t = (x_clip - x0) / (x1 - x0) + if 0 <= t <= 1: + Iy = y0 + t * (y1 - y0) + I = np.array([x_clip, Iy]) # noqa: E741 + return I, t + return None, None + + +class DummyDI: + """Stand-in for ``tidy3d.components.autograd.derivative_utils.DerivativeInfo``.""" + + def __init__( + self, + *, + paths, + axis: int, + coeffs: dict[str, float], + bounds_intersect: Optional[tuple[tuple[float, ...], tuple[float, ...]]] = None, + ) -> None: + self.paths = paths + self.axis = axis + self.a = coeffs["a"] + self.b = coeffs["b"] + self.c = coeffs["c"] + self.d = coeffs["d"] + self.frequency = 200e12 + self.eps_in = 12.0 + self.interpolators = None + + self.bounds_intersect = ( + bounds_intersect + if bounds_intersect is not None + else ((-1e3, -1e3, -1e3), (1e3, 1e3, 1e3)) + ) + + adaptive_vjp_spacing = DerivativeInfo.adaptive_vjp_spacing + + def create_interpolators(self, dtype=None): + return {} + + def evaluate_gradient_at_points( + self, spatial_coords, normals, perps1, perps2, interpolators=None + ): + centers = spatial_coords + plane_axes = [i for i in (0, 1, 2) if i != self.axis] + u, v = centers[:, plane_axes[0]], centers[:, plane_axes[1]] + w = centers[:, self.axis] + + vals = self.a * u + self.b * v + self.c * w + self.d + return vals + + +def analytic_faces(verts: np.ndarray, coeffs: dict[str, float], z0: float, z1: float): + """Return the (bottom, top) face forces with our sign convention.""" + area, mx, my = polygon_area_centroid(verts) + + bot = -(coeffs["a"] * mx + coeffs["b"] * my + (coeffs["c"] * z0 + coeffs["d"]) * area) + top = coeffs["a"] * mx + coeffs["b"] * my + (coeffs["c"] * z1 + coeffs["d"]) * area + return bot, top + + +def analytic_vertex_forces( + verts: np.ndarray, coeffs: dict[str, float], z0: float, z1: float +) -> np.ndarray: + """ + Return per-vertex forces projected onto the polygon plane, + using weighted distribution (1-s, s) consistent with linear shape functions. + """ + a, b, c, d = coeffs["a"], coeffs["b"], coeffs["c"], coeffs["d"] + thickness = z1 - z0 + n_verts = len(verts) + vf = np.zeros_like(verts, dtype=float) + + v0 = verts + v1 = np.roll(verts, -1, axis=0) + seg = v1 - v0 + L = np.linalg.norm(seg, axis=1) # segment length (N,) + L_safe = np.where(L <= np.finfo(float).eps, 1.0, L) + + # ensure normal calculation handles potential zero length segments safely + n = np.zeros_like(seg) + valid_edge = L > np.finfo(float).eps + n[valid_edge] = ( + np.stack([seg[valid_edge, 1], -seg[valid_edge, 0]], axis=1) / L_safe[valid_edge, None] + ) + + x0, y0 = v0[:, 0], v0[:, 1] + x1, y1 = v1[:, 0], v1[:, 1] + + z_integral_term_half = L * (c / 4.0) * (z1**2 - z0**2) + + # weighted scalar contribution from edge i to vertex i + F_scalar_i = ( + L * thickness * ((a / 6.0) * (2 * x0 + x1) + (b / 6.0) * (2 * y0 + y1) + d / 2.0) + + z_integral_term_half + ) + + # weighted scalar contribution from edge 'i' to vertex 'i+1' + F_scalar_i_plus_1 = ( + L * thickness * ((a / 6.0) * (x0 + 2 * x1) + (b / 6.0) * (y0 + 2 * y1) + d / 2.0) + + z_integral_term_half + ) + + for i in range(n_verts): + if not valid_edge[i]: + continue + vf[i] += F_scalar_i[i] * n[i] + vf[(i + 1) % n_verts] += F_scalar_i_plus_1[i] * n[i] + + return vf + + +@pytest.mark.parametrize("axis", [0, 1, 2]) +class TestPolySlab3D: + """3d test for arbitrary extrusion axis.""" + + @pytest.fixture + def slab(self, axis): + return td.PolySlab(vertices=VERTS_2D, axis=axis, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab, axis): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=axis, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_face_forces(self, results): + bot_exp, top_exp = analytic_faces(VERTS_2D, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_vertex_forces(self, results): + vf_exp = analytic_vertex_forces(VERTS_2D, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("vertices",)], vf_exp, rtol=1e-2) + + +class TestPolySlab2DInPlane: + """Simulation slice exactly through the slab mid-plane (``is_2d == True``).""" + + AXIS = 2 + + @pytest.fixture(autouse=True) + def _setup(self): + self.slab = td.PolySlab(vertices=VERTS_2D, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + z_mid = 0.5 * sum(SLAB_BOUNDS) + self.di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + bounds_intersect=((-1e3, -1e3, z_mid), (1e3, 1e3, z_mid)), + ) + self.results = self.slab._compute_derivatives(self.di) + self.z_mid = z_mid + + def test_faces_are_zero(self): + assert self.results[("slab_bounds", 0)] == 0.0 + assert self.results[("slab_bounds", 1)] == 0.0 + + def test_vertex_forces(self): + verts = VERTS_2D + coeffs = COEFFS + z_mid = self.z_mid + a, b, c, d = coeffs["a"], coeffs["b"], coeffs["c"], coeffs["d"] + n_verts = len(verts) + vf = np.zeros_like(verts, dtype=float) # Use float + + v0 = verts + v1 = np.roll(verts, -1, axis=0) + seg = v1 - v0 + L = np.linalg.norm(seg, axis=1) + valid_edge = L > np.finfo(float).eps + L_safe = np.where(valid_edge, L, 1.0) + n = np.zeros_like(seg) + n[valid_edge] = ( + np.stack([seg[valid_edge, 1], -seg[valid_edge, 0]], axis=1) / L_safe[valid_edge, None] + ) + + x0, y0 = v0[:, 0], v0[:, 1] + x1, y1 = v1[:, 0], v1[:, 1] + + # calculate k = (a*x(s) + b*y(s) + c*z_mid + d) + k_at_z_mid_common_half = (c * z_mid + d) / 2.0 + + # weighted scalar contribution to vertex 'i' (start, weight 1-s) + F_scalar_i = L * ( + (a / 6.0) * (2 * x0 + x1) + (b / 6.0) * (2 * y0 + y1) + k_at_z_mid_common_half + ) + + # weighted scalar contribution to vertex 'i+1' (end, weight s) + F_scalar_i_plus_1 = L * ( + (a / 6.0) * (x0 + 2 * x1) + (b / 6.0) * (y0 + 2 * y1) + k_at_z_mid_common_half + ) + + for i in range(n_verts): + if not valid_edge[i]: + continue + vf[i] += F_scalar_i[i] * n[i] + vf[(i + 1) % n_verts] += F_scalar_i_plus_1[i] * n[i] + + npt.assert_allclose(self.results[("vertices",)], vf, rtol=1e-2) + + +class TestPolySlab2DCrossSection: + """Case where the slab surface intersects a vertical clipping plane.""" + + AXIS = 2 + X_CLIP = 1.5 # x-coordinate of the clipping plane + + @classmethod + def setup_class(cls): + cls.slab = td.PolySlab(vertices=VERTS_2D, axis=cls.AXIS, slab_bounds=SLAB_BOUNDS) + + sim_min = (-1e3, -1e3, -1e3) + sim_max = (cls.X_CLIP, 1e3, 1e3) + + cls.di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=cls.AXIS, + coeffs=COEFFS, + bounds_intersect=(sim_min, sim_max), + ) + cls.results = cls.slab._compute_derivatives(cls.di) + + # intersection geometry: line segments at x == X_CLIP + poly = sgeom.Polygon(VERTS_2D) + line = sgeom.LineString([(cls.X_CLIP, -1e3), (cls.X_CLIP, 1e3)]) + inter = poly.intersection(line) + + if inter.is_empty: + cls.y_segments: list[list[tuple[float, float]]] = [] + elif isinstance(inter, sgeom.MultiLineString): + cls.y_segments = [list(seg.coords) for seg in inter.geoms] + else: # single segment + cls.y_segments = [list(inter.coords)] + + @classmethod + def _analytic_face(cls, z) -> float: + """Exact integral over the clipped face x <= X_CLIP.""" + poly = sgeom.Polygon(VERTS_2D) + + clip = sgeom.box(-1e3, -1e3, cls.X_CLIP, 1e3) + face = poly.intersection(clip) + + if face.is_empty: + return 0.0 + + face = orient(face, sign=1.0) + + verts = np.asarray(face.exterior.coords[:-1]) + area, mx, my = polygon_area_centroid(verts) + + a_, b_, c_, d_ = (COEFFS[k] for k in ("a", "b", "c", "d")) + return a_ * mx + b_ * my + (c_ * z + d_) * area + + @staticmethod + def _integrate_weighted_term(p0, p1, t_start, t_end, weight_s): + """Integrates ((1-s)p0 + s p1) * weight(s) ds from t_start to t_end.""" + t2_end, t3_end = t_end * t_end, t_end * t_end * t_end + t2_start, t3_start = t_start * t_start, t_start * t_start * t_start + + if weight_s == "s": + val_end = p0 * (0.5 * t2_end - t3_end / 3.0) + p1 * (t3_end / 3.0) + val_start = p0 * (0.5 * t2_start - t3_start / 3.0) + p1 * (t3_start / 3.0) + return val_end - val_start + else: # weight 1-s + val_end = p0 * (t_end - t2_end + t3_end / 3.0) + p1 * (0.5 * t2_end - t3_end / 3.0) + val_start = p0 * (t_start - t2_start + t3_start / 3.0) + p1 * ( + 0.5 * t2_start - t3_start / 3.0 + ) + return val_end - val_start + + @staticmethod + def _vertex_forces_clipped( + original_verts: np.ndarray, + x_clip: float, + coeffs: dict[str, float], + z0: float, + z1: float, + ) -> np.ndarray: + """ + Exact force on each original vertex after clipping ``x <= x_clip``, + by directly integrating k*N_j over the clipped portion of each original edge. + """ + a, b, c, d = coeffs["a"], coeffs["b"], coeffs["c"], coeffs["d"] + thickness = z1 - z0 + n_original_verts = len(original_verts) + original_vf = np.zeros_like(original_verts, dtype=float) + + v0_all = original_verts + v1_all = np.roll(original_verts, -1, axis=0) + + for i in range(n_original_verts): + v0, v1 = v0_all[i], v1_all[i] + x0, y0 = v0 + x1, y1 = v1 + + seg = v1 - v0 + L = np.linalg.norm(seg) + valid_edge = L > np.finfo(float).eps + if not valid_edge: + continue + + n = np.array([seg[1], -seg[0]]) / L # outward normal + + # determine intersection parameter t (0<=t<=1) for x=x_clip + t_intersect = 1.0 # full edge potentially inside + if not np.isclose(x0, x1): + t_cand = (x_clip - x0) / (x1 - x0) + if 0 < t_cand < 1: + t_intersect = t_cand + + tol = 1e-9 + inside0 = x0 <= x_clip + tol + inside1 = x1 <= x_clip + tol + + t_start, t_end = 0.0, 1.0 + + if not inside0 and not inside1: # fully outside + continue + elif inside0 and not inside1: # starts inside, ends outside + t_end = t_intersect + elif not inside0 and inside1: # starts outside, ends inside + t_start = t_intersect + + if t_end <= t_start + tol: + continue + + t_start = max(0.0, t_start) + t_end = min(1.0, t_end) + if t_end <= t_start: + continue + + # integrate terms weighted by (1-s) for vertex v0 (index i) + int_s_w0 = (t_end - 0.5 * t_end**2) - (t_start - 0.5 * t_start**2) + int_x_w0 = TestPolySlab2DCrossSection._integrate_weighted_term( + x0, x1, t_start, t_end, "1-s" + ) + int_y_w0 = TestPolySlab2DCrossSection._integrate_weighted_term( + y0, y1, t_start, t_end, "1-s" + ) + + # integrate terms weighted by s for vertex v1 (index i+1) + int_s_w1 = (0.5 * t_end**2) - (0.5 * t_start**2) + int_x_w1 = TestPolySlab2DCrossSection._integrate_weighted_term( + x0, x1, t_start, t_end, "s" + ) + int_y_w1 = TestPolySlab2DCrossSection._integrate_weighted_term( + y0, y1, t_start, t_end, "s" + ) + + # combine with z-integration and coefficients + z_int_val = 0.5 * (z1**2 - z0**2) + + # scalar force contribution to v0 + F_scalar_i = L * ( + (a * int_x_w0 + b * int_y_w0 + d * int_s_w0) * thickness + c * z_int_val * int_s_w0 + ) + # scalar force contribution to v1 + F_scalar_i_plus_1 = L * ( + (a * int_x_w1 + b * int_y_w1 + d * int_s_w1) * thickness + c * z_int_val * int_s_w1 + ) + + original_vf[i] += F_scalar_i * n + original_vf[(i + 1) % n_original_verts] += F_scalar_i_plus_1 * n + + return original_vf + + def test_vertex_forces(self): + vf_exp = self._vertex_forces_clipped(VERTS_2D, self.X_CLIP, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(self.results[("vertices",)], vf_exp, rtol=1e-2) + + +class TestPolySlabShortEdges: + """Test with very short edges to trigger ``n_uniform <= 3`` quadrature path. + + This test uses a small square with edge lengths of 0.05 units. Based on the + quadrature selection logic in ``PolySlab.get_adaptive_samples()``, edges this short + should trigger the direct Gauss quadrature path with very few points, as + ``n_uniform = edge_length / adaptive_vjp_spacing`` will be <= 3. + """ + + AXIS = 2 + # square with very small edge lengths (0.05 units) + SHORT_EDGE_VERTS = np.array( + [ + (0.0, 0.0), + (0.05, 0.0), + (0.05, 0.05), + (0.0, 0.05), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self): + return td.PolySlab(vertices=self.SHORT_EDGE_VERTS, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_face_forces(self, results): + bot_exp, top_exp = analytic_faces(self.SHORT_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_vertex_forces(self, results): + vf_exp = analytic_vertex_forces(self.SHORT_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("vertices",)], vf_exp, rtol=1e-2) + + +class TestPolySlabLongEdges: + """Test with very long edges to trigger composite Gauss quadrature (n_gauss > 7). + + This test uses a rectangle with 20-unit long edges. For typical ``adaptive_vjp_spacing`` + values (around 0.1-1.0 wavelength fraction), this results in n_uniform >> 3, + leading to n_gauss > 7, which triggers the composite Gauss quadrature path that + breaks the edge into segments with 4-point quadrature each. + """ + + AXIS = 2 + # rectangle with very long edges (20 units) + LONG_EDGE_VERTS = np.array( + [ + (0.0, 0.0), + (20.0, 0.0), + (20.0, 1.0), + (0.0, 1.0), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self): + return td.PolySlab(vertices=self.LONG_EDGE_VERTS, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_face_forces(self, results): + bot_exp, top_exp = analytic_faces(self.LONG_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_vertex_forces(self, results): + vf_exp = analytic_vertex_forces(self.LONG_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("vertices",)], vf_exp, rtol=1e-2) + + +class TestPolySlabMixedEdges: + """Test with mixed edge lengths in the same polygon. + + This test creates a polygon with edges of varying lengths to verify that the + implementation correctly handles different quadrature methods on different edges + within the same polygon: + - Very short edges (0.05 units): Should use direct Gauss quadrature with few points + - Medium edge (0.95 units): Should use direct Gauss-Legendre quadrature + - Long edges (10+ units): Should use composite Gauss quadrature + + This tests the robustness of the edge-by-edge quadrature selection. + """ + + AXIS = 2 + # polygon with both very short and very long edges + MIXED_EDGE_VERTS = np.array( + [ + (0.0, 0.0), + (10.0, 0.0), # long edge: 10 units + (10.0, 0.05), # very short edge: 0.05 units + (10.05, 0.05), # very short edge: 0.05 units + (10.05, 1.0), # medium edge: 0.95 units + (0.0, 1.0), # long edge: 10.05 units + ], + dtype=float, + ) + + @pytest.fixture + def slab(self): + return td.PolySlab(vertices=self.MIXED_EDGE_VERTS, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_face_forces(self, results): + bot_exp, top_exp = analytic_faces(self.MIXED_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_vertex_forces(self, results): + vf_exp = analytic_vertex_forces(self.MIXED_EDGE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("vertices",)], vf_exp, rtol=1e-2) + + +class TestPolySlabDegenerateEdges: + """Test with near-degenerate edges to verify numerical stability. + + Note: We use small edges (0.001) rather than truly degenerate edges + (duplicate vertices) because PolySlab validation rejects invalid polygons. + This tests numerical stability for very small but valid edge lengths. + """ + + AXIS = 2 + + @pytest.fixture + def degenerate_verts(self): + # pentagon with one small edge to test numerical stability + return np.array( + [ + (0.0, 0.0), + (1.0, 0.0), + (1.0, 0.001), # small edge but above validator tolerance + (1.0, 1.0), + (0.0, 1.0), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self, degenerate_verts): + return td.PolySlab(vertices=degenerate_verts, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_derivatives_are_finite(self, results): + """Ensure derivatives don't have NaN or inf values.""" + for path, value in results.items(): + if isinstance(value, np.ndarray): + assert np.all(np.isfinite(value)), f"Non-finite values in {path}" + else: + assert np.isfinite(value), f"Non-finite value in {path}" + + def test_face_forces(self, results, degenerate_verts): + # test face forces for polygons with small edges + bot_exp, top_exp = analytic_faces(degenerate_verts, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + +@pytest.mark.parametrize( + "edge_length,expected_path", + [ + (0.02, "short"), # very short edge: n_uniform <= 3 + (0.05, "short"), # short edge: n_uniform <= 3 + (0.5, "medium"), # medium edge: direct Gauss quadrature (n_gauss <= 7) + (2.0, "composite"), # long edge: composite quadrature (n_gauss > 7) + (10.0, "composite"), # long edge: composite quadrature + (50.0, "composite"), # very long edge: composite quadrature + ], +) +class TestQuadraturePaths: + """Parametrized test to verify correct quadrature path selection based on edge length.""" + + AXIS = 2 + + @pytest.fixture + def square_verts(self, edge_length): + """Create a square with the specified edge length.""" + return np.array( + [ + (0.0, 0.0), + (edge_length, 0.0), + (edge_length, edge_length), + (0.0, edge_length), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self, square_verts): + return td.PolySlab(vertices=square_verts, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + def test_correct_quadrature_path(self, slab, edge_length, expected_path): + """Verify that the expected quadrature path is used for the given edge length.""" + di = DummyDI( + paths=[("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + + # get the adaptive spacing to compute expected path + # this is not super elegant because it literally copies the implementation + # but it's better than nothing... + dx = di.adaptive_vjp_spacing() + n_uniform = max(1, int(np.ceil(edge_length / dx))) + + if n_uniform <= 3: + actual_path = "short" + else: + n_gauss = max(2, int(n_uniform * 0.4)) + if n_gauss <= 7: + actual_path = "medium" + else: + actual_path = "composite" + + assert actual_path == expected_path, ( + f"Edge length {edge_length} with dx={dx:.6f} gives n_uniform={n_uniform}, " + f"expected {expected_path} path but got {actual_path}" + ) + + # also verify the derivatives are computed correctly + results = slab._compute_derivatives(di) + assert ("vertices",) in results + assert results[("vertices",)].shape == (4, 2) + + +class TestPolySlabConcave: + """Test with concave polygons.""" + + AXIS = 2 + # L-shaped concave polygon + CONCAVE_VERTS = np.array( + [ + (0.0, 0.0), + (2.0, 0.0), + (2.0, 1.0), + (1.0, 1.0), + (1.0, 2.0), + (0.0, 2.0), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self): + return td.PolySlab(vertices=self.CONCAVE_VERTS, axis=self.AXIS, slab_bounds=SLAB_BOUNDS) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_face_forces(self, results): + bot_exp, top_exp = analytic_faces(self.CONCAVE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_vertex_forces(self, results): + vf_exp = analytic_vertex_forces(self.CONCAVE_VERTS, COEFFS, *SLAB_BOUNDS) + npt.assert_allclose(results[("vertices",)], vf_exp, rtol=1e-2) + + +@pytest.mark.parametrize("sidewall_angle", [0.0, np.pi / 12, np.pi / 6]) +class TestPolySlabSidewallAngles: + """Test with different sidewall angles. + + Note: We use angles up to pi/6 instead of larger angles like pi/4 + because large sidewall angles with the given slab thickness can cause + self-intersecting geometry, which fails PolySlab validation. + """ + + AXIS = 2 + TRIANGLE_VERTS = np.array( + [ + (0.0, 0.0), + (2.0, 0.0), + (1.0, 1.5), + ], + dtype=float, + ) + + @pytest.fixture + def slab(self, sidewall_angle): + return td.PolySlab( + vertices=self.TRIANGLE_VERTS, + axis=self.AXIS, + slab_bounds=SLAB_BOUNDS, + sidewall_angle=sidewall_angle, + ) + + @pytest.fixture + def results(self, slab): + di = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1), ("vertices",)], + axis=self.AXIS, + coeffs=COEFFS, + ) + return slab._compute_derivatives(di) + + def test_derivatives_are_finite(self, results): + """Ensure derivatives are finite for slanted sidewalls.""" + for path, value in results.items(): + if isinstance(value, np.ndarray): + assert np.all(np.isfinite(value)), f"Non-finite values in {path}" + else: + assert np.isfinite(value), f"Non-finite value in {path}" + + def test_face_forces_scale_with_polygon_area(self, slab, results, sidewall_angle): + """Face forces should scale with the actual polygon areas at each face.""" + base_polygon = slab.base_polygon + top_polygon = slab.top_polygon + + bot_exp, _ = analytic_faces(base_polygon, COEFFS, *SLAB_BOUNDS) + _, top_exp = analytic_faces(top_polygon, COEFFS, *SLAB_BOUNDS) + + npt.assert_allclose(results[("slab_bounds", 0)], bot_exp, rtol=1e-2) + npt.assert_allclose(results[("slab_bounds", 1)], top_exp, rtol=1e-2) + + def test_face_force_area_relationship(self, slab, results, sidewall_angle): + """Verify that face forces scale linearly with polygon areas.""" + if sidewall_angle == 0.0: + return + + base_area, _, _ = polygon_area_centroid(slab.base_polygon) + top_area, _, _ = polygon_area_centroid(slab.top_polygon) + ref_area, _, _ = polygon_area_centroid(self.TRIANGLE_VERTS) + + # for a linear integrand f(x,y,z) = ax + by + cz + d, + # the force scales with area when the centroid term dominates + # this is a sanity check that the implementation is consistent + + # get the reference case (vertical sidewalls) + slab_vertical = td.PolySlab( + vertices=self.TRIANGLE_VERTS, + axis=self.AXIS, + slab_bounds=SLAB_BOUNDS, + sidewall_angle=0.0, + ) + di_vertical = DummyDI( + paths=[("slab_bounds", 0), ("slab_bounds", 1)], + axis=self.AXIS, + coeffs=COEFFS, + ) + results_vertical = slab_vertical._compute_derivatives(di_vertical) + + # check that the force ratios are reasonable compared to area ratios + # we don't expect exact proportionality due to centroid shifts, + # but the relationship should be monotonic and roughly linear + bot_force_ratio = results[("slab_bounds", 0)] / results_vertical[("slab_bounds", 0)] + top_force_ratio = results[("slab_bounds", 1)] / results_vertical[("slab_bounds", 1)] + + bot_area_ratio = base_area / ref_area + top_area_ratio = top_area / ref_area + + # forces should increase/decrease in the same direction as areas + assert (bot_force_ratio > 1.0) == (bot_area_ratio > 1.0), ( + f"Bottom force ratio {bot_force_ratio} inconsistent with area ratio {bot_area_ratio}" + ) + assert (top_force_ratio > 1.0) == (top_area_ratio > 1.0), ( + f"Top force ratio {top_force_ratio} inconsistent with area ratio {top_area_ratio}" + ) diff --git a/tests/test_components/test_autograd_symmetry_numerical.py b/tests/test_components/test_autograd_symmetry_numerical.py new file mode 100644 index 0000000000..4153de9c1f --- /dev/null +++ b/tests/test_components/test_autograd_symmetry_numerical.py @@ -0,0 +1,366 @@ +# test autograd for field sources when symmetry is used in the simulation +from __future__ import annotations + +import operator +import sys + +import autograd as ag +import matplotlib.pylab as plt +import numpy as np +import pytest + +import tidy3d as td +import tidy3d.web as web + +PLOT_SYMMETRY_COMPARISON = False +NUM_FINITE_DIFFERENCE = 10 +SAVE_FD_ADJ_DATA = False +SAVE_FD_LOC = 0 +SAVE_ADJ_LOC = 1 +LOCAL_GRADIENT = False +VERBOSE = False +NUMERICAL_RESULTS_DATA_DIR = "./numerical_symmetry_test/" +SHOW_PRINT_STATEMENTS = True + +RMS_THRESHOLD = 0.25 + +if PLOT_SYMMETRY_COMPARISON: + pytestmark = pytest.mark.usefixtures("mpl_config_interactive") +else: + pytestmark = pytest.mark.usefixtures("mpl_config_noninteractive") + +if SHOW_PRINT_STATEMENTS: + sys.stdout = sys.stderr + + +FINITE_DIFF_PERM_SEED = 1.5**2 +MESH_FACTOR_DESIGN = 30.0 + + +def get_sim_geometry(mesh_wvl_um): + return td.Box(size=(5 * mesh_wvl_um, 5 * mesh_wvl_um, 7 * mesh_wvl_um), center=(0, 0, 0)) + + +def make_base_sim( + mesh_wvl_um, + adj_wvl_um, + monitor_size_wvl, + box_for_override, + symmetry, + monitor_bg_index=1.0, + run_time=1e-11, +): + sim_geometry = get_sim_geometry(mesh_wvl_um) + sim_size_um = sim_geometry.size + sim_center_um = sim_geometry.center + + boundary_spec = td.BoundarySpec( + x=td.Boundary.pml(), + y=td.Boundary.pml(), + z=td.Boundary.pml(), + ) + + dl_design = mesh_wvl_um / MESH_FACTOR_DESIGN + + mesh_overrides = [] + mesh_overrides.extend( + [ + td.MeshOverrideStructure( + geometry=box_for_override, + dl=[dl_design, dl_design, dl_design], + ), + ] + ) + + src_size = sim_size_um[0:2] + (0,) + + wl_min_src_um = 0.9 * adj_wvl_um + wl_max_src_um = 1.1 * adj_wvl_um + + fwidth_src = td.C_0 * ((1.0 / wl_min_src_um) - (1.0 / wl_max_src_um)) + freq0 = td.C_0 / adj_wvl_um + + pulse = td.GaussianPulse(freq0=freq0, fwidth=fwidth_src) + + src = td.PlaneWave( + center=(0, 0, -2 * mesh_wvl_um), + size=(td.inf, td.inf, 0), + direction="+", + pol_angle=0, + angle_theta=0, + source_time=pulse, + ) + + field_monitor = td.FieldMonitor( + center=(0, 0, 0.25 * sim_size_um[2]), + size=tuple(dim * mesh_wvl_um for dim in monitor_size_wvl), + name="monitor_fields", + freqs=[freq0], + ) + + monitor_index_block = td.Box( + center=(0, 0, 0.25 * sim_size_um[2] + mesh_wvl_um), + size=(*tuple(2 * size for size in sim_size_um[0:2]), mesh_wvl_um + 0.5 * sim_size_um[2]), + ) + monitor_index_block_structure = td.Structure( + geometry=monitor_index_block, medium=td.Medium(permittivity=monitor_bg_index**2) + ) + + sim_base = td.Simulation( + center=sim_center_um, + size=sim_size_um, + grid_spec=td.GridSpec.auto( + min_steps_per_wvl=30, + wavelength=mesh_wvl_um, + override_structures=mesh_overrides, + ), + structures=[monitor_index_block_structure], + sources=[src], + monitors=[field_monitor], + run_time=run_time, + boundary_spec=boundary_spec, + subpixel=True, + symmetry=symmetry, + ) + + return sim_base + + +def create_objective_functions(geometry, create_sim_base, eval_fn, sim_path_dir): + def objective_(perm_array, symmetry): + sim_base = create_sim_base(symmetry) + + block_structure = td.Structure.from_permittivity_array( + eps_data=perm_array, + geometry=geometry, + ) + + sim_with_block = sim_base.updated_copy(structures=(*sim_base.structures, block_structure)) + + sim_data = web.run( + sim_with_block, + task_name="symmetry_field_testing", + local_gradient=LOCAL_GRADIENT, + verbose=VERBOSE, + ) + + objective_val = eval_fn(sim_data) + + return objective_val + + def objective_no_symmetry(perm_array): + return objective_(perm_array=perm_array, symmetry=(0, 0, 0)) + + def objective_x_symmetry(perm_array): + return objective_(perm_array=perm_array, symmetry=(-1, 0, 0)) + + def objective_y_symmetry(perm_array): + return objective_(perm_array=perm_array, symmetry=(0, 1, 0)) + + def objective_xy_symmetry(perm_array): + return objective_(perm_array=perm_array, symmetry=(-1, 1, 0)) + + return objective_no_symmetry, objective_x_symmetry, objective_y_symmetry, objective_xy_symmetry + + +def make_eval_fns(monitor_size_wvl): + num_nonzero_spatial_dims = 3 - np.sum(np.isclose(monitor_size_wvl, 0)) + + def intensity(sim_data): + field_data = sim_data["monitor_fields"] + shape_x, shape_y, shape_z, *_ = field_data.Ex.values.shape + + return np.sum(np.abs(field_data.Ex.values) ** 2 + np.abs(field_data.Ey.values) ** 2) + + eval_fns = [intensity] + eval_fn_names = ["intensity"] + + if num_nonzero_spatial_dims == 2: + + def flux(sim_data): + field_data = sim_data["monitor_fields"] + + return np.sum(field_data.flux.values) + + eval_fns.append(flux) + eval_fn_names.append("flux") + + return eval_fns, eval_fn_names + + +background_indices = [1.0] +mesh_wvls_um = [1.55] +adj_wvls_um = [1.55] +monitor_sizes_3d_wvl = [(0.5, 0.5, 0)] + +field_symmetry_test_parameters = [] + +test_number = 0 +for idx in range(len(mesh_wvls_um)): + mesh_wvl_um = mesh_wvls_um[idx] + adj_wvl_um = adj_wvls_um[idx] + + for monitor_size_wvl in monitor_sizes_3d_wvl: + eval_fns, eval_fn_names = make_eval_fns(monitor_size_wvl) + + for monitor_bg_index in background_indices: + for eval_fn_idx, eval_fn in enumerate(eval_fns): + field_symmetry_test_parameters.append( + { + "mesh_wvl_um": mesh_wvl_um, + "adj_wvl_um": adj_wvl_um, + "monitor_size_wvl": monitor_size_wvl, + "monitor_bg_index": monitor_bg_index, + "eval_fn": eval_fn, + "eval_fn_name": eval_fn_names[eval_fn_idx], + "test_number": test_number, + } + ) + + test_number += 1 + + +@pytest.mark.numerical +@pytest.mark.parametrize( + "field_symmetry_test_parameters, dir_name", + zip( + field_symmetry_test_parameters, + ([NUMERICAL_RESULTS_DATA_DIR] if SAVE_FD_ADJ_DATA else [None]) + * len(field_symmetry_test_parameters), + ), + indirect=["dir_name"], +) +def test_adjoint_difference_symmetry( + field_symmetry_test_parameters, rng, tmp_path, create_directory +): + """Test the gradient is not affected by symmetry when using field sources.""" + + num_tests = 0 + for monitor_size_wvl in monitor_sizes_3d_wvl: + eval_fns, _ = make_eval_fns(monitor_size_wvl) + num_tests += len(eval_fns) * len(background_indices) * len(mesh_wvls_um) + + test_results = np.zeros((2, NUM_FINITE_DIFFERENCE)) + + test_number = field_symmetry_test_parameters["test_number"] + + ( + mesh_wvl_um, + adj_wvl_um, + monitor_size_wvl, + monitor_bg_index, + eval_fn, + eval_fn_name, + test_number, + ) = operator.itemgetter( + "mesh_wvl_um", + "adj_wvl_um", + "monitor_size_wvl", + "monitor_bg_index", + "eval_fn", + "eval_fn_name", + "test_number", + )(field_symmetry_test_parameters) + + dim_um = mesh_wvl_um + dim_um = mesh_wvl_um + thickness_um = 0.5 * mesh_wvl_um + block = td.Box(center=(0, 0, 0), size=(dim_um, dim_um, thickness_um)) + + dim = 1 + int(dim_um / (mesh_wvl_um / MESH_FACTOR_DESIGN)) + Nz = 1 + int(thickness_um / (mesh_wvl_um / MESH_FACTOR_DESIGN)) + + sim_geometry = get_sim_geometry(mesh_wvl_um) + + box_for_override = td.Box( + center=(0, 0, 0), size=sim_geometry.size[0:2] + (thickness_um + mesh_wvl_um,) + ) + + eval_fns, eval_fn_names = make_eval_fns(monitor_size_wvl) + + sim_path_dir = tmp_path / f"test{test_number}" + sim_path_dir.mkdir() + + objective_no_symmetry, objective_x_symmetry, objective_y_symmetry, objective_xy_symmetry = ( + create_objective_functions( + block, + lambda symmetry, + mesh_wvl_um=mesh_wvl_um, + adj_wvl_um=adj_wvl_um, + monitor_size_wvl=monitor_size_wvl, + box_for_override=box_for_override, + monitor_bg_index=monitor_bg_index: make_base_sim( + mesh_wvl_um=mesh_wvl_um, + adj_wvl_um=adj_wvl_um, + monitor_size_wvl=monitor_size_wvl, + box_for_override=box_for_override, + monitor_bg_index=monitor_bg_index, + symmetry=symmetry, + ), + eval_fn, + sim_path_dir=str(sim_path_dir), + ) + ) + + obj_val_and_grad_no_symmetry = ag.value_and_grad(objective_no_symmetry) + obj_val_and_grad_x_symmetry = ag.value_and_grad(objective_x_symmetry) + obj_val_and_grad_y_symmetry = ag.value_and_grad(objective_y_symmetry) + obj_val_and_grad_xy_symmetry = ag.value_and_grad(objective_xy_symmetry) + + objs_val_and_grad = [ + obj_val_and_grad_no_symmetry, + obj_val_and_grad_x_symmetry, + obj_val_and_grad_y_symmetry, + obj_val_and_grad_xy_symmetry, + ] + + symmetries = ["none", "x", "y", "xy"] + + objs = [] + adj_grads = [] + + perm_init = FINITE_DIFF_PERM_SEED * np.ones((dim, dim, Nz)) + + for obj_val_and_grad in objs_val_and_grad: + obj, adj_grad = obj_val_and_grad(perm_init) + + objs.append(obj) + adj_grads.append(np.array(adj_grad)) + + grad_data_base = adj_grads[0] / objs[0] + for idx in range(1, len(adj_grads)): + # field magnitudes can be different for different symmetries so we expect the gradients + # to scale with the objecive values + grad_data = adj_grads[idx] / objs[idx] + + mag_base = np.sqrt(np.mean(grad_data_base**2)) + mag_compare = np.sqrt(np.mean(grad_data**2)) + rms_error = np.sqrt(np.mean((grad_data_base - grad_data) ** 2)) + + if SHOW_PRINT_STATEMENTS: + print(f"Testing {eval_fn_name} objective") + print(f"Symmetry comparison: {symmetries[0]}, {symmetries[idx]}") + print(f"RMS error (normalized): {rms_error / np.sqrt(mag_base * mag_compare)}") + + assert np.isclose(rms_error / np.sqrt(mag_base * mag_compare), 0.0, atol=0.075), ( + "Expected adjoint gradients to be the same with and without symmetry" + ) + + if PLOT_SYMMETRY_COMPARISON: + plot_grad_data_base = np.squeeze(grad_data_base) + plot_grad_data = np.squeeze(grad_data) + plot_diff = plot_grad_data - plot_grad_data_base + + plt.subplot(1, 3, 1) + plt.imshow(plot_grad_data_base[:, :, plot_grad_data_base.shape[2] // 2]) + plt.title(f"Symmetry: {symmetries[0]}") + plt.colorbar() + plt.subplot(1, 3, 2) + plt.imshow(plot_grad_data[:, :, plot_grad_data.shape[2] // 2]) + plt.title(f"Symmetry: {symmetries[idx]}") + plt.colorbar() + plt.subplot(1, 3, 3) + plt.imshow(plot_diff[:, :, plot_diff.shape[2] // 2]) + plt.title("Difference") + plt.colorbar() + plt.show() diff --git a/tests/test_components/test_base.py b/tests/test_components/test_base.py index 9058ec0897..1a82febfe3 100644 --- a/tests/test_components/test_base.py +++ b/tests/test_components/test_base.py @@ -1,7 +1,10 @@ """Tests the base model.""" +from __future__ import annotations + import numpy as np import pytest + import tidy3d as td from tidy3d.components.base import Tidy3dBaseModel @@ -79,15 +82,15 @@ def test_deep_copy(): # assert id(s.geometry) != id(s_kwargs.geometry) # behavior of modifying attributes - s_default = s.copy(update=dict(geometry=td.Sphere(radius=1.0))) + s_default = s.copy(update={"geometry": td.Sphere(radius=1.0)}) assert id(s.geometry) != id(s_default.geometry) # s_shallow = s.copy(deep=False, update=dict(geometry=Sphere(radius=1.0))) # assert id(s.geometry) != id(s_shallow.geometry) # behavior of modifying attributes of attributes - new_geometry = s.geometry.copy(update=dict(size=(2, 2, 2))) - s_default = s.copy(update=dict(geometry=new_geometry)) + new_geometry = s.geometry.copy(update={"size": (2, 2, 2)}) + s_default = s.copy(update={"geometry": new_geometry}) assert id(s.geometry) != id(s_default.geometry) # s_shallow = s.copy(deep=False) @@ -111,7 +114,7 @@ def test_updated_copy(): s2 = s.updated_copy(medium=m2, geometry=b2) assert s2.geometry == b2 assert s2.medium == m2 - s3 = s.updated_copy(**{"medium": m2, "geometry": b2}) + s3 = s.updated_copy(medium=m2, geometry=b2) assert s3 == s2 diff --git a/tests/test_components/test_bc_placement.py b/tests/test_components/test_bc_placement.py index 6c1a1fcf70..f11bc82756 100644 --- a/tests/test_components/test_bc_placement.py +++ b/tests/test_components/test_bc_placement.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from tidy3d.components.bc_placement import ( MediumMediumInterface, SimulationBoundary, diff --git a/tests/test_components/test_beam.py b/tests/test_components/test_beam.py index 457ad28292..a5686ed2d5 100644 --- a/tests/test_components/test_beam.py +++ b/tests/test_components/test_beam.py @@ -1,8 +1,11 @@ """Tests for the various BeamProfile components.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pd import pytest + from tidy3d.components.beam import ( AstigmaticGaussianBeamProfile, GaussianBeamProfile, diff --git a/tests/test_components/test_boundaries.py b/tests/test_components/test_boundaries.py index 9ca0f7d915..3c190919ca 100644 --- a/tests/test_components/test_boundaries.py +++ b/tests/test_components/test_boundaries.py @@ -1,9 +1,15 @@ """Tests boundary conditions.""" +from __future__ import annotations + import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.boundary import ( + MIN_NUM_ABSORBER_LAYERS, + MIN_NUM_PML_LAYERS, + MIN_NUM_STABLE_PML_LAYERS, PML, Absorber, BlochBoundary, @@ -70,7 +76,7 @@ def test_boundaryedge_types(plane_wave_dir): def test_boundary_validators(): - """Test the validators in class `Boundary`""" + """Test the validators in class ``Boundary``""" bloch = BlochBoundary(bloch_vec=1) pec = PECBoundary() @@ -88,20 +94,20 @@ def test_boundary_validators(): @pytest.mark.parametrize("boundary, log_level", [(PMCBoundary(), None), (Periodic(), "WARNING")]) def test_boundary_validator_warnings(boundary, log_level): - """Test the validators in class `Boundary` which should show a warning but not an error""" + """Test the validators in class ``Boundary`` which should show a warning but not an error""" with AssertLogLevel(log_level): _ = Boundary(plus=PECBoundary(), minus=boundary) @pytest.mark.parametrize("boundary, log_level", [(PMCBoundary(), None), (Periodic(), "WARNING")]) def test_boundary_validator_warnings_switched(boundary, log_level): - """Test the validators in class `Boundary` which should show a warning but not an error""" + """Test the validators in class ``Boundary`` which should show a warning but not an error""" with AssertLogLevel(log_level): _ = Boundary(minus=PECBoundary(), plus=boundary) def test_boundary(): - """Test that the various classmethods and combinations for Boundary work correctly.""" + """Test that the various classmethods and combinations for ``Boundary`` to work correctly.""" # periodic boundary = Boundary.periodic() @@ -141,7 +147,7 @@ def test_boundary(): def test_boundaryspec_classmethods(): - """Test that the classmethods for BoundarySpec work correctly.""" + """Test that the classmethods for ``BoundarySpec`` work correctly.""" # pml boundary_spec = BoundarySpec.pml(x=False, y=True, z=True) @@ -185,3 +191,26 @@ def test_boundaryspec_classmethods(): assert all( isinstance(boundary, PML) for boundary_dim in boundaries for boundary in boundary_dim ) + + +@pytest.mark.parametrize("absorber_type", [PML, StablePML, Absorber]) +def test_num_layers_validator(absorber_type): + """Test the Field validators that enforce ``num_layers>0``.""" + with pytest.raises(pydantic.ValidationError): + _ = absorber_type(num_layers=0) + + +@pytest.mark.parametrize( + "absorber_type, num_layers", + [ + (PML, MIN_NUM_PML_LAYERS), + (StablePML, MIN_NUM_STABLE_PML_LAYERS), + (Absorber, MIN_NUM_ABSORBER_LAYERS), + ], +) +def test_num_layers_validator_warning(absorber_type, num_layers): + """Test the validators in ``PML`` which should display a warning not an error.""" + with AssertLogLevel(None): + _ = absorber_type(num_layers=num_layers) + with AssertLogLevel("WARNING"): + _ = absorber_type(num_layers=num_layers - 1) diff --git a/tests/test_components/test_custom.py b/tests/test_components/test_custom.py index 4ba744f054..0c9dbd4662 100644 --- a/tests/test_components/test_custom.py +++ b/tests/test_components/test_custom.py @@ -1,13 +1,14 @@ """Tests custom sources and mediums.""" -from typing import Tuple +from __future__ import annotations import dill as pickle import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td import xarray as xr + +import tidy3d as td from tidy3d.components.data.dataset import PermittivityDataset from tidy3d.components.data.utils import UnstructuredGridDataset, _get_numpy_array from tidy3d.components.medium import ( @@ -40,7 +41,7 @@ def make_scalar_data(): """Makes a scalar field data array.""" data = np.random.random((Nx, Ny, Nz, 1)) + 1 - return td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + return td.ScalarFieldDataArray(data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) def make_scalar_data_multifreqs(): @@ -48,7 +49,7 @@ def make_scalar_data_multifreqs(): Nfreq = 2 freqs_mul = [2e14, 3e14] data = np.random.random((Nx, Ny, Nz, Nfreq)) - return td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=freqs_mul)) + return td.ScalarFieldDataArray(data, coords={"x": X, "y": Y, "z": Z, "f": freqs_mul}) def make_custom_field_source(): @@ -77,7 +78,7 @@ def make_spatial_data(value=0, dx=0, unstructured=False, seed=None, uniform=Fals data = value * np.ones((Nx, Ny, Nz)) else: data = np.random.random((Nx, Ny, Nz)) + value - arr = td.SpatialDataArray(data, coords=dict(x=X + dx, y=Y, z=Z)) + arr = td.SpatialDataArray(data, coords={"x": X + dx, "y": Y, "z": Z}) if unstructured: method = "direct" if uniform else "linear" return cartesian_to_unstructured(arr, seed=seed, method=method) @@ -89,7 +90,7 @@ def make_spatial_data(value=0, dx=0, unstructured=False, seed=None, uniform=Fals CURRENT_SRC = make_custom_current_source() -def get_dataset(custom_source_obj) -> Tuple[str, td.FieldDataset]: +def get_dataset(custom_source_obj) -> tuple[str, td.FieldDataset]: """Get a dict containing dataset depending on type and its key.""" if isinstance(custom_source_obj, td.CustomFieldSource): return "field_dataset", custom_source_obj.field_dataset @@ -115,7 +116,7 @@ def test_custom_source_simulation(source): def test_validator_tangential_field(): """Test that it errors if no tangential field defined.""" field_dataset = FIELD_SRC.field_dataset - field_dataset = field_dataset.copy(update=dict(Ex=None, Ez=None, Hx=None, Hz=None)) + field_dataset = field_dataset.copy(update={"Ex": None, "Ez": None, "Hx": None, "Hz": None}) with pytest.raises(pydantic.ValidationError): _ = td.CustomFieldSource(size=SIZE, source_time=ST, field_dataset=field_dataset) @@ -123,7 +124,7 @@ def test_validator_tangential_field(): def test_validator_non_planar(): """Test that it errors if the source geometry has a volume.""" field_dataset = FIELD_SRC.field_dataset - field_dataset = field_dataset.copy(update=dict(Ex=None, Ez=None, Hx=None, Hz=None)) + field_dataset = field_dataset.copy(update={"Ex": None, "Ez": None, "Hx": None, "Hz": None}) with pytest.raises(pydantic.ValidationError): _ = td.CustomFieldSource(size=(1, 1, 1), source_time=ST, field_dataset=field_dataset) @@ -132,8 +133,8 @@ def test_validator_non_planar(): def test_validator_freq_out_of_range_src(source): """Test that it errors if field_dataset frequency out of range of source_time.""" key, dataset = get_dataset(source) - Ex_new = td.ScalarFieldDataArray(dataset.Ex.data, coords=dict(x=X, y=Y, z=Z, f=[0])) - dataset_fail = dataset.copy(update=dict(Ex=Ex_new)) + Ex_new = td.ScalarFieldDataArray(dataset.Ex.data, coords={"x": X, "y": Y, "z": Z, "f": [0]}) + dataset_fail = dataset.copy(update={"Ex": Ex_new}) with pytest.raises(pydantic.ValidationError): _ = source.updated_copy(size=SIZE, source_time=ST, **{key: dataset_fail}) @@ -143,8 +144,8 @@ def test_validator_freq_multiple(source): """Test that it errors more than 1 frequency given.""" key, dataset = get_dataset(source) new_data = np.concatenate((dataset.Ex.data, dataset.Ex.data), axis=-1) - Ex_new = td.ScalarFieldDataArray(new_data, coords=dict(x=X, y=Y, z=Z, f=[1, 2])) - dataset_fail = dataset.copy(update=dict(Ex=Ex_new)) + Ex_new = td.ScalarFieldDataArray(new_data, coords={"x": X, "y": Y, "z": Z, "f": [1, 2]}) + dataset_fail = dataset.copy(update={"Ex": Ex_new}) with pytest.raises(pydantic.ValidationError): _ = source.copy(update={key: dataset_fail}) @@ -321,7 +322,7 @@ def test_medium_raw(): # lossy data = np.random.random((Nx, Ny, Nz, 1)) + 1 + 1e-2 * 1j - eps_raw = td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + eps_raw = td.ScalarFieldDataArray(data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) eps_raw_s = td.SpatialDataArray(eps_raw.squeeze(dim="f", drop=True)) eps_raw_u = cartesian_to_unstructured(eps_raw_s, pert=0.01, method="nearest") med = CustomMedium.from_eps_raw(eps_raw) @@ -374,7 +375,7 @@ def test_medium_interp(unstructured): Nx = 1 X = [1.1] data = np.random.random((Nx, Ny, Nz, 1)) - orig_data = td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + orig_data = td.ScalarFieldDataArray(data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) if unstructured: orig_data = cartesian_to_unstructured(orig_data.isel(f=0), pert=0.2, method="linear") @@ -414,7 +415,7 @@ def test_medium_smaller_than_one_positive_sigma(unstructured): # eps_inf < 1 n_data = 1 + np.random.random((Nx, Ny, Nz, 1)) n_data[0, 0, 0, 0] = 0.5 - n_dataarray = td.ScalarFieldDataArray(n_data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + n_dataarray = td.ScalarFieldDataArray(n_data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) if unstructured: n_dataarray = cartesian_to_unstructured(n_dataarray.isel(f=0)) @@ -426,8 +427,8 @@ def test_medium_smaller_than_one_positive_sigma(unstructured): n_data = 1 + np.random.random((Nx, Ny, Nz, 1)) k_data = np.random.random((Nx, Ny, Nz, 1)) k_data[0, 0, 0, 0] = -0.1 - n_dataarray = td.ScalarFieldDataArray(n_data, coords=dict(x=X, y=Y, z=Z, f=freqs)) - k_dataarray = td.ScalarFieldDataArray(k_data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + n_dataarray = td.ScalarFieldDataArray(n_data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) + k_dataarray = td.ScalarFieldDataArray(k_data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) if unstructured: n_dataarray = cartesian_to_unstructured(n_dataarray.isel(f=0), seed=1) @@ -622,7 +623,7 @@ def make_scalar_data_f(): """Makes a scalar field data array with random f.""" data = np.random.random((Nx, Ny, Nz, 1)) + 1 return td.ScalarFieldDataArray( - data, coords=dict(x=X, y=Y, z=Z, f=[freqs[0] * np.random.random(1)[0]]) + data, coords={"x": X, "y": Y, "z": Z, "f": [freqs[0] * np.random.random(1)[0]]} ) # same f and different f diff --git a/tests/test_components/test_eme.py b/tests/test_components/test_eme.py index 0e9c617607..bf30e940f1 100644 --- a/tests/test_components/test_eme.py +++ b/tests/test_components/test_eme.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import numpy as np import pydantic.v1 as pd import pytest -import tidy3d as td from matplotlib import pyplot as plt + +import tidy3d as td from tidy3d.exceptions import SetupError, ValidationError from ..utils import AssertLogLevel @@ -311,10 +314,12 @@ def test_eme_simulation(): with AssertLogLevel("INFO", contains_str="wavelength"): sim = sim.updated_copy(grid_spec=grid_spec) # multiple freqs are ok, but not for autogrid - _ = sim.updated_copy(grid_spec=td.GridSpec.uniform(dl=0.2), freqs=[1e10] + list(sim.freqs)) + _ = sim.updated_copy( + grid_spec=td.GridSpec.uniform(dl=0.2), freqs=[10000000000.0, *list(sim.freqs)] + ) with AssertLogLevel("INFO", contains_str="wavelength"): _ = sim.updated_copy( - freqs=list(sim.freqs) + [1e10], + freqs=[*list(sim.freqs), 10000000000.0], grid_spec=grid_spec, ) @@ -610,15 +615,15 @@ def _get_eme_scalar_mode_field_data_array(num_sweep=0): sweep_index = np.arange(num_sweep) else: sweep_index = [0] - coords = dict( - x=x, - y=y, - z=z, - f=f, - sweep_index=sweep_index, - eme_cell_index=eme_cell_index, - mode_index=mode_index, - ) + coords = { + "x": x, + "y": y, + "z": z, + "f": f, + "sweep_index": sweep_index, + "eme_cell_index": eme_cell_index, + "mode_index": mode_index, + } data = td.EMEScalarModeFieldDataArray( (1 + 1j) * np.random.random( @@ -647,15 +652,15 @@ def _get_eme_scalar_field_data_array(num_sweep=0): sweep_index = np.arange(num_sweep) else: sweep_index = [0] - coords = dict( - x=x, - y=y, - z=z, - f=f, - sweep_index=sweep_index, - eme_port_index=eme_port_index, - mode_index=mode_index, - ) + coords = { + "x": x, + "y": y, + "z": z, + "f": f, + "sweep_index": sweep_index, + "eme_port_index": eme_port_index, + "mode_index": mode_index, + } data = td.EMEScalarFieldDataArray( (1 + 1j) * np.random.random((len(x), len(y), len(z), 2, len(sweep_index), 2, 5)), coords=coords, @@ -689,9 +694,12 @@ def _get_eme_smatrix_data_array(num_modes_in=2, num_modes_out=3, num_freqs=2, nu data = (1 + 1j) * np.random.random( (len(f), len(mode_index_out), len(mode_index_in), len(sweep_index)) ) - coords = dict( - f=f, mode_index_out=mode_index_out, mode_index_in=mode_index_in, sweep_index=sweep_index - ) + coords = { + "f": f, + "mode_index_out": mode_index_out, + "mode_index_in": mode_index_in, + "sweep_index": sweep_index, + } smatrix_entry = td.EMESMatrixDataArray(data, coords=coords) if num_modes_in == 0: @@ -730,14 +738,14 @@ def _get_eme_coeff_data_array(num_sweep=0): sweep_index = np.arange(num_sweep) else: sweep_index = [0] - coords = dict( - f=f, - sweep_index=sweep_index, - eme_port_index=eme_port_index, - eme_cell_index=eme_cell_index, - mode_index_out=mode_index_out, - mode_index_in=mode_index_in, - ) + coords = { + "f": f, + "sweep_index": sweep_index, + "eme_port_index": eme_port_index, + "eme_cell_index": eme_cell_index, + "mode_index_out": mode_index_out, + "mode_index_in": mode_index_in, + } data = td.EMECoefficientDataArray( (1 + 1j) * np.random.random( @@ -776,9 +784,12 @@ def _get_eme_mode_index_data_array(num_sweep=0): sweep_index = np.arange(num_sweep) else: sweep_index = [0] - coords = dict( - f=f, sweep_index=sweep_index, eme_cell_index=eme_cell_index, mode_index=mode_index - ) + coords = { + "f": f, + "sweep_index": sweep_index, + "eme_cell_index": eme_cell_index, + "mode_index": mode_index, + } data = td.EMEModeIndexDataArray( (1 + 1j) * np.random.random((len(f), len(sweep_index), len(eme_cell_index), len(mode_index))), @@ -800,14 +811,14 @@ def test_eme_smatrix_data_array(): def _get_eme_mode_solver_dataset(num_sweep=0): n_complex = _get_eme_mode_index_data_array(num_sweep=num_sweep) field = _get_eme_scalar_mode_field_data_array(num_sweep=num_sweep) - fields = {key: field for key in ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"]} + fields = dict.fromkeys(["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], field) return td.EMEModeSolverDataset(n_complex=n_complex, **fields) def _get_eme_field_dataset(num_sweep=0): field = _get_eme_scalar_field_data_array(num_sweep=num_sweep) - fields = {key: field for key in ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"]} + fields = dict.fromkeys(["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], field) return td.EMEFieldDataset(**fields) @@ -851,12 +862,12 @@ def _get_eme_mode_solver_data(num_sweep=0): ) ) grid_dual_correction_data = grid_primal_correction_data - grid_correction_coords = dict( - f=n_complex.f, - sweep_index=sweep_index, - eme_cell_index=n_complex.eme_cell_index, - mode_index=n_complex.mode_index, - ) + grid_correction_coords = { + "f": n_complex.f, + "sweep_index": sweep_index, + "eme_cell_index": n_complex.eme_cell_index, + "mode_index": n_complex.mode_index, + } grid_primal_correction = td.components.data.data_array.EMEFreqModeDataArray( grid_primal_correction_data, coords=grid_correction_coords ) @@ -956,14 +967,14 @@ def test_eme_sim_data(): port_modes = _get_eme_port_modes() smatrix = _get_eme_smatrix_dataset(num_modes_1=5, num_modes_2=5) - sim_data = td.EMESimulationData(simulation=sim, data=data, smatrix=smatrix, port_modes=None) + sim_data = td.EMESimulationData(simulation=sim, data=data, smatrix=smatrix, port_modes_raw=None) with pytest.raises(SetupError): _ = sim_data.port_modes_tuple with pytest.raises(SetupError): _ = sim_data.port_modes_list_sweep sim_data = td.EMESimulationData( - simulation=sim, data=data, smatrix=smatrix, port_modes=port_modes + simulation=sim, data=data, smatrix=smatrix, port_modes_raw=port_modes ) _ = sim_data.port_modes_tuple _ = sim_data.port_modes_list_sweep @@ -1017,11 +1028,11 @@ def test_eme_sim_data(): assert len(smatrix_in_basis.S22.coords) == 1 with pytest.raises(SetupError): - _ = sim_data.updated_copy(port_modes=None).smatrix_in_basis( + _ = sim_data.updated_copy(port_modes_raw=None).smatrix_in_basis( modes1=modes_in_data, modes2=modes_out_data ) with pytest.raises(SetupError): - _ = sim_data.updated_copy(port_modes=None).field_in_basis( + _ = sim_data.updated_copy(port_modes_raw=None).field_in_basis( field=sim_data["field"], modes=modes_in_data, port_index=0 ) @@ -1081,7 +1092,7 @@ def test_eme_sim_data(): smatrix = _get_eme_smatrix_dataset(num_modes_1=5, num_modes_2=5, num_sweep=10) sim = sim.updated_copy(sweep_spec=td.EMELengthSweep(scale_factors=np.linspace(1, 2, 10))) sim_data = td.EMESimulationData( - simulation=sim, data=data, smatrix=smatrix, port_modes=port_modes + simulation=sim, data=data, smatrix=smatrix, port_modes_raw=port_modes ) # test smatrix_in_basis @@ -1149,11 +1160,19 @@ def test_eme_sim_data(): _ = sim_data.port_modes_tuple assert len(sim_data.port_modes_list_sweep) == 1 + with AssertLogLevel("WARNING", contains_str="flux"): + _ = sim_data._extract_mode_solver_data( + data=sim_data.port_modes.updated_copy( + monitor=sim.port_modes_monitor.updated_copy(size=(0, td.inf, td.inf)) + ), + eme_cell_index=0, + ) + # test freq sweep smatrix_in_basis sim = sim.updated_copy(sweep_spec=td.EMEFreqSweep(freq_scale_factors=np.linspace(1, 2, 10))) port_modes = _get_eme_port_modes(num_sweep=10) sim_data = td.EMESimulationData( - simulation=sim, data=data, smatrix=smatrix, port_modes=port_modes + simulation=sim, data=data, smatrix=smatrix, port_modes_raw=port_modes ) with pytest.raises(SetupError): _ = sim_data.port_modes_tuple diff --git a/tests/test_components/test_field_projection.py b/tests/test_components/test_field_projection.py index 94d1e0d552..d6047d4727 100644 --- a/tests/test_components/test_field_projection.py +++ b/tests/test_components/test_field_projection.py @@ -1,8 +1,11 @@ """Test near field to far field transformations.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.field_projection import FieldProjector from tidy3d.exceptions import DataError @@ -165,7 +168,7 @@ def test_proj_data(tmp_path): r = np.atleast_1d(5) theta = np.linspace(0, np.pi, 10) phi = np.linspace(0, 2 * np.pi, 20) - coords_tp = dict(r=r, theta=theta, phi=phi, f=f) + coords_tp = {"r": r, "theta": theta, "phi": phi, "f": f} values_tp = (1 + 1j) * np.random.random((len(r), len(theta), len(phi), len(f))) scalar_field_tp = td.FieldProjectionAngleDataArray(values_tp, coords=coords_tp) monitor_tp = td.FieldProjectionAngleMonitor( @@ -185,7 +188,7 @@ def test_proj_data(tmp_path): x = np.linspace(0, 5, 10) y = np.linspace(0, 10, 20) z = np.atleast_1d(5) - coords_xy = dict(x=x, y=y, z=z, f=f) + coords_xy = {"x": x, "y": y, "z": z, "f": f} values_xy = (1 + 1j) * np.random.random((len(x), len(y), len(z), len(f))) scalar_field_xy = td.FieldProjectionCartesianDataArray(values_xy, coords=coords_xy) monitor_xy = td.FieldProjectionCartesianMonitor( @@ -212,7 +215,7 @@ def test_proj_data(tmp_path): ux = np.linspace(0, 0.4, 10) uy = np.linspace(0, 0.6, 20) r = np.atleast_1d(5) - coords_u = dict(ux=ux, uy=uy, r=r, f=f) + coords_u = {"ux": ux, "uy": uy, "r": r, "f": f} values_u = (1 + 1j) * np.random.random((len(ux), len(uy), len(r), len(f))) scalar_field_u = td.FieldProjectionKSpaceDataArray(values_u, coords=coords_u) monitor_u = td.FieldProjectionKSpaceMonitor( @@ -244,7 +247,7 @@ def test_proj_data(tmp_path): x = np.linspace(0, 5, 10) y = np.linspace(0, 10, 20) z = np.atleast_1d(5) - coords_xy = dict(x=x, y=y, z=z, f=f) + coords_xy = {"x": x, "y": y, "z": z, "f": f} values_xy = (1 + 1j) * np.random.random((len(x), len(y), len(z), len(f))) scalar_field_xy = td.FieldProjectionCartesianDataArray(values_xy, coords=coords_xy) _ = td.FieldProjectionCartesianMonitor( @@ -290,7 +293,7 @@ def test_proj_clientside(): y = np.linspace(-1, 1, 10) z = np.array([0.0]) f = [f0] - coords = dict(x=x, y=y, z=z, f=f) + coords = {"x": x, "y": y, "z": z, "f": f} scalar_field = td.ScalarFieldDataArray( (1 + 1j) * np.random.random((10, 10, 1, 1)), coords=coords ) @@ -469,7 +472,7 @@ def make_2d_proj(plane): x = np.array([0.0]) y = np.linspace(-1, 1, 10) z = np.array([0.0]) - coords = dict(x=x, y=y, z=z, f=[f0]) + coords = {"x": x, "y": y, "z": z, "f": [f0]} scalar_field = td.ScalarFieldDataArray( (1 + 1j) * np.random.random((1, 10, 1, 1)), coords=coords ) @@ -486,7 +489,7 @@ def make_2d_proj(plane): x = np.array([0.0]) y = np.array([0.0]) z = np.linspace(-1, 1, 10) - coords = dict(x=x, y=y, z=z, f=[f0]) + coords = {"x": x, "y": y, "z": z, "f": [f0]} scalar_field = td.ScalarFieldDataArray( (1 + 1j) * np.random.random((1, 1, 10, 1)), coords=coords ) @@ -503,7 +506,7 @@ def make_2d_proj(plane): x = np.array([0.0]) y = np.array([0.0]) z = np.linspace(-1, 1, 10) - coords = dict(x=x, y=y, z=z, f=[f0]) + coords = {"x": x, "y": y, "z": z, "f": [f0]} scalar_field = td.ScalarFieldDataArray( (1 + 1j) * np.random.random((1, 1, 10, 1)), coords=coords ) diff --git a/tests/test_components/test_freq_range.py b/tests/test_components/test_freq_range.py new file mode 100644 index 0000000000..7c30a5e03c --- /dev/null +++ b/tests/test_components/test_freq_range.py @@ -0,0 +1,188 @@ +"""Test class ``FreqRange`` for frequency and wavelength handling.""" + +from __future__ import annotations + +import numpy as np + +import tidy3d.constants as td_const +from tidy3d.components.source.freq_range import FreqRange +from tidy3d.components.source.time import GaussianPulse + + +def test_constructor(): + """ + test construction of ``FreqRange`` from central frequency + ``freq0`` and bandwidth ``fwidth``. + """ + # set initial params + freq0 = 1e9 # set central frequency + fwidth = 1e8 # set one-side bandwidth + + # construct instance of FreqRange class + freq_range = FreqRange(freq0=freq0, fwidth=fwidth) + + fmin = freq0 - fwidth + fmax = freq0 + fwidth + + lmin = td_const.C_0 / fmax + lmax = td_const.C_0 / fmin + + # validated if class atributes were initialized correctly + assert freq_range.fmin == fmin + assert freq_range.fmax == fmax + assert freq_range.lda0 == (lmin + lmax) / 2 + assert freq_range.freq0 == freq0 + assert freq_range.fwidth == fwidth + + +def test_from_freq_interval(): + """ + test construction of ``FreqRange`` from frequency interval. + """ + + fmin = 1e10 # new min frequency + fmax = 1e11 # new max frequency + + lmin = td_const.C_0 / fmax + lmax = td_const.C_0 / fmin + + # update object given new frequencies + freq_range = FreqRange.from_freq_interval(fmin=fmin, fmax=fmax) + + # validate if frequencies were updated correctly + assert freq_range.fmin == fmin + assert freq_range.fmax == fmax + assert np.isclose(freq_range.freq0, (fmin + fmax) / 2, rtol=1e-14) + assert np.isclose(freq_range.fwidth, (fmax - fmin) / 2, rtol=1e-14) + assert np.isclose(freq_range.lda0, (lmin + lmax) / 2, rtol=1e-14) + + +def test_from_wavelength(): + """ + test construction of ``FreqRange`` from a central wavelength and a wavelength. + """ + # set initial params + wvl0 = 1 + wvl_width = 0.1 + + # get the shortest and the longest wavelengths + wvl_min = wvl0 - wvl_width + wvl_max = wvl0 + wvl_width + + # define frequency range + freq_range = FreqRange.from_wavelength(wvl0=wvl0, wvl_width=wvl_width) + + # + assert freq_range.lda0 == wvl0 + + fmin = td_const.C_0 / wvl_max + fmax = td_const.C_0 / wvl_min + + assert np.isclose(freq_range.fmin, fmin, rtol=1e-14) + assert np.isclose(freq_range.fmax, fmax, rtol=1e-14) + assert np.isclose(freq_range.freq0, 0.5 * (fmin + fmax), rtol=1e-14) + assert np.isclose(freq_range.fwidth, 0.5 * (fmax - fmin), rtol=1e-14) + + +def test_from_wvl_interval(): + """ + test construction of ``FreqRange`` from an interval of wavelengths. + """ + # set initial params + wvl_min = 0.1 + wvl_max = 1 + fmin = td_const.C_0 / wvl_max + fmax = td_const.C_0 / wvl_min + + # freq_range = FreqRange(freq0, fwidth) + + # update frequencies based on wavelength + freq_range = FreqRange.from_wvl_interval(wvl_min=wvl_min, wvl_max=wvl_max) + + # ensure that parameters are updated correctly + assert np.isclose(freq_range.lda0, (wvl_min + wvl_max) / 2, rtol=1e-14) + assert np.isclose(freq_range.freq0, 0.5 * (fmin + fmax), rtol=1e-14) + assert np.isclose(freq_range.fmax, fmax, rtol=1e-14) + assert np.isclose(freq_range.fmin, fmin, rtol=1e-14) + assert np.isclose(freq_range.fwidth, 0.5 * (fmax - fmin), rtol=1e-14) + + +def test_freqs(): + """ + test generation of uniformly distributed frequency samples + from a given frequency interval. + """ + # set initial params + freq0 = 1e9 # set central frequency + fwidth = 1e8 # set one-side bandwidth + num_points = 11 + + # construct instance of FreqRange class + freq_range = FreqRange(freq0=freq0, fwidth=fwidth) + + # form sampling frequency points + freqs = freq_range.freqs(num_points=num_points) + + # make sure + assert np.array_equal(freqs, np.linspace(freq0 - fwidth, freq0 + fwidth, num_points)) + + # reset number of sampling points to 1 + num_points = 1 + freqs = freq_range.freqs(num_points=num_points) + + # check if freqs == freq0 + assert np.array_equal(freqs, np.array([freq0])) + + +def test_ldas(): + """ + test generation of uniformly distributed wavelength samples + from a given wavelength interval. + """ + # set initial params + freq0 = 1e9 # set central frequency + fwidth = 1e8 # set one-side bandwidth + num_points = 11 + + lmin = td_const.C_0 / (freq0 + fwidth) + lmax = td_const.C_0 / (freq0 - fwidth) + lda0 = (lmin + lmax) / 2 + + # construct instance of FreqRange class + freq_range = FreqRange(freq0=freq0, fwidth=fwidth) + + # form sampling frequency points + ldas = freq_range.ldas(num_points=num_points) + + # make sure + assert np.array_equal(ldas, np.linspace(lmin, lmax, num_points)) + + # reset number of sampling points to 1 + num_points = 1 + ldas = freq_range.ldas(num_points=num_points) + + # check if freqs == freq0 + assert np.array_equal(ldas, np.array([lda0])) + + +def test_gaussian_pulse(): + """ + test generation of a ``GaussianPulse`` with frequency parameters + defined in ``FreqRange``. + """ + + # set initial params + freq0 = 1e9 # set central frequency + fwidth = 1e8 # set one-side bandwidth + fmin = freq0 - fwidth + fmax = freq0 + fwidth + + # construct instance of FreqRange class + freq_range = FreqRange(freq0=freq0, fwidth=fwidth) + + pulse_exp = GaussianPulse.from_frequency_range( + fmin=fmin, fmax=fmax + ) # instantiate GaussianPulse explicitly + pulse_imp = freq_range.to_gaussian_pulse() # get instance by calling a method gaussian_pulse() + + assert pulse_exp == pulse_imp # compare two pulses diff --git a/tests/test_components/test_frequencies.py b/tests/test_components/test_frequencies.py index 30c8f25716..a066f0c395 100644 --- a/tests/test_components/test_frequencies.py +++ b/tests/test_components/test_frequencies.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import numpy as np import pytest + import tidy3d as td diff --git a/tests/test_components/test_geometry.py b/tests/test_components/test_geometry.py index 160885de2e..6fb6f6ae3d 100644 --- a/tests/test_components/test_geometry.py +++ b/tests/test_components/test_geometry.py @@ -1,17 +1,21 @@ """Tests Geometry objects.""" +from __future__ import annotations + import math import warnings -import gdspy import gdstk import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest import shapely -import tidy3d as td import trimesh + +import tidy3d as td +from tidy3d.compat import _shapely_is_older_than +from tidy3d.components.geometry.base import cleanup_shapely_object from tidy3d.components.geometry.mesh import AREA_SIZE_THRESHOLD from tidy3d.components.geometry.utils import ( SnapBehavior, @@ -183,7 +187,7 @@ def test_zero_dims(): def test_inside_polyslab_sidewall(): - ps = POLYSLAB.copy(update=dict(sidewall_angle=0.1)) + ps = POLYSLAB.copy(update={"sidewall_angle": 0.1}) ps.inside(x=0, y=0, z=0) @@ -284,7 +288,7 @@ def test_box_from_bounds(): def test_polyslab_center_axis(): """Test the handling of center_axis in a polyslab having (-td.inf, td.inf) bounds.""" - ps = POLYSLAB.copy(update=dict(slab_bounds=(-td.inf, td.inf))) + ps = POLYSLAB.copy(update={"slab_bounds": (-td.inf, td.inf)}) assert ps.center_axis == 0 @@ -293,7 +297,7 @@ def test_polyslab_center_axis(): ) def test_polyslab_inf_bounds(lower_bound, upper_bound): """Test the handling of various operations in a polyslab having inf bounds.""" - ps = POLYSLAB.copy(update=dict(slab_bounds=(lower_bound, upper_bound))) + ps = POLYSLAB.copy(update={"slab_bounds": (lower_bound, upper_bound)}) # catch any runtime warning related to inf operations with warnings.catch_warnings(): warnings.simplefilter("error") @@ -327,28 +331,28 @@ def test_polyslab_inf_to_finite_bounds(axis): vertices=[[0, 0], [2.5, 1], [2, 3], [0.5, 4], [-1.5, 2.5]], ) - assert ps_low_inf.finite_length_axis == ( - LARGE_NUMBER + axis_bound - ), "Unexpected finite length for polyslab axis with -inf bound" - assert ps_high_inf.finite_length_axis == ( - LARGE_NUMBER + axis_bound - ), "Unexpected finite length for polyslab axis with inf bound" - assert ( - ps_inf.finite_length_axis == 2 * LARGE_NUMBER - ), "Unexpected finite length for polyslab axis with two inf bounds" + assert ps_low_inf.finite_length_axis == (LARGE_NUMBER + axis_bound), ( + "Unexpected finite length for polyslab axis with -inf bound" + ) + assert ps_high_inf.finite_length_axis == (LARGE_NUMBER + axis_bound), ( + "Unexpected finite length for polyslab axis with inf bound" + ) + assert ps_inf.finite_length_axis == 2 * LARGE_NUMBER, ( + "Unexpected finite length for polyslab axis with two inf bounds" + ) def test_validate_polyslab_vertices_valid(): with pytest.raises(pydantic.ValidationError): - POLYSLAB.copy(update=dict(vertices=(1, 2, 3))) + POLYSLAB.copy(update={"vertices": (1, 2, 3)}) with pytest.raises(pydantic.ValidationError): crossing_verts = ((0, 0), (1, 1), (0, 1), (1, 0)) - POLYSLAB.copy(update=dict(vertices=crossing_verts)) + POLYSLAB.copy(update={"vertices": crossing_verts}) def test_sidewall_failed_validation(): with pytest.raises(pydantic.ValidationError): - POLYSLAB.copy(update=dict(sidewall_angle=1000)) + POLYSLAB.copy(update={"sidewall_angle": 1000}) def test_surfaces(): @@ -379,14 +383,6 @@ def test_gdstk_cell(): ) -def test_gdspy_cell(): - gds_cell = gdspy.Cell("name") - gds_cell.add(gdspy.Rectangle((0, 0), (1, 1))) - td.PolySlab.from_gds(gds_cell=gds_cell, axis=2, slab_bounds=(-1, 1), gds_layer=0) - with pytest.raises(Tidy3dKeyError): - td.PolySlab.from_gds(gds_cell=gds_cell, axis=2, slab_bounds=(-1, 1), gds_layer=1) - - def make_geo_group(): """Make a generic Geometry Group.""" boxes = [td.Box(size=(1, 1, 1), center=(i, 0, 0)) for i in range(-5, 5)] @@ -437,16 +433,16 @@ def test_geometryoperations(): assert UNION + CYLINDER == td.GeometryGroup( geometries=(UNION.geometry_a, UNION.geometry_b, CYLINDER) ) - assert BOX + GROUP == td.GeometryGroup(geometries=(BOX,) + GROUP.geometries) - assert GROUP + CYLINDER == td.GeometryGroup(geometries=GROUP.geometries + (CYLINDER,)) + assert BOX + GROUP == td.GeometryGroup(geometries=(BOX, *GROUP.geometries)) + assert GROUP + CYLINDER == td.GeometryGroup(geometries=(*GROUP.geometries, CYLINDER)) assert BOX | CYLINDER == td.GeometryGroup(geometries=(BOX, CYLINDER)) assert BOX | UNION == td.GeometryGroup(geometries=(BOX, UNION.geometry_a, UNION.geometry_b)) assert UNION | CYLINDER == td.GeometryGroup( geometries=(UNION.geometry_a, UNION.geometry_b, CYLINDER) ) - assert BOX | GROUP == td.GeometryGroup(geometries=(BOX,) + GROUP.geometries) - assert GROUP | CYLINDER == td.GeometryGroup(geometries=GROUP.geometries + (CYLINDER,)) + assert BOX | GROUP == td.GeometryGroup(geometries=(BOX, *GROUP.geometries)) + assert GROUP | CYLINDER == td.GeometryGroup(geometries=(*GROUP.geometries, CYLINDER)) assert BOX * SPHERE == td.ClipOperation( operation="intersection", geometry_a=BOX, geometry_b=SPHERE @@ -1049,7 +1045,7 @@ def test_custom_surface_geometry(tmp_path): def test_geo_group_sim(): geo_grp = td.TriangleMesh.from_stl("tests/data/two_boxes_separate.stl") geos_orig = list(geo_grp.geometries) - geo_grp_full = geo_grp.updated_copy(geometries=geos_orig + [td.Box(size=(1, 1, 1))]) + geo_grp_full = geo_grp.updated_copy(geometries=[*geos_orig, td.Box(size=(1, 1, 1))]) sim = td.Simulation( size=(10, 10, 10), @@ -1172,3 +1168,133 @@ def test_triangulation_with_collinear_vertices(): xr = np.linspace(0, 1, 6) a = np.array([[x, -0.5] for x in xr] + [[x, 0.5] for x in xr[::-1]]) assert len(td.components.geometry.triangulation.triangulate(a)) == 10 + + +def test_triangle_mesh_from_height(): + """Test the TriangleMesh.from_height_function and from_height_grid constructors.""" + + # Test successful creation with a valid height function + def valid_height_func(x, y): + return 0.5 + 0.2 * np.sin(4 * (x + 1)) * np.cos(3 * y) + + axis = 2 + direction = "+" + base = 0.0 + center = [0, 0] + size = [1.5, 2] + grid_size = [20, 15] + + geometry_from_func = td.TriangleMesh.from_height_function( + axis=axis, + direction=direction, + base=base, + center=center, + size=size, + grid_size=grid_size, + height_func=valid_height_func, + ) + + assert isinstance(geometry_from_func, td.TriangleMesh) + + # Test equivalence with from_height_grid method + x = np.linspace(center[0] - 0.5 * size[0], center[0] + 0.5 * size[0], grid_size[0]) + y = np.linspace(center[1] - 0.5 * size[1], center[1] + 0.5 * size[1], grid_size[1]) + x_mesh, y_mesh = np.meshgrid(x, y, indexing="ij") + + geometry_from_grid = td.TriangleMesh.from_height_grid( + axis=axis, + direction=direction, + base=base, + grid=(x, y), + height=valid_height_func(x_mesh, y_mesh), + ) + + # Check if the two TriangleMesh objects are equivalent + assert geometry_from_func == geometry_from_grid + + # Test ValueError for negative height values + def negative_height_func(x, y): + return 0.5 + 0.2 * np.sin(4 * (x + 1)) * np.cos(3 * y) - 2 + + with pytest.raises( + ValueError, + match="All height values must be non-negative.", + ): + td.TriangleMesh.from_height_function( + axis=axis, + direction=direction, + base=base, + center=center, + size=size, + grid_size=grid_size, + height_func=negative_height_func, + ) + + # Test ValueError for height_func returning ndarray with wrong shape + def wrong_shape_height_func(x, y): + return np.zeros((3, 3)) # Incorrect shape + + expected_shape = (grid_size[0], grid_size[1]) + + # Test for the presence of key parts of the error message + with pytest.raises(ValueError) as excinfo: + td.TriangleMesh.from_height_function( + axis=axis, + direction=direction, + base=base, + center=center, + size=size, + grid_size=grid_size, + height_func=wrong_shape_height_func, + ) + # Check that the error message contains the expected information + error_message = str(excinfo.value) + assert f"shape {expected_shape}" in error_message + assert "shape (3, 3)" in error_message + + +def test_cleanup_shapely_object(): + if _shapely_is_older_than("2.1"): + # (Old versions of shapely don't support `shapely.make_valid()` with the correct arguments. + # However older alternatives like `.buffer(0)` are not as robust. `.buffer(0)` is likely + # to generate polygons which look correct, but have extra vertices, causing test to fail. + # So if `shapely.make_valid()` is not supported, the safest thing to do is skip this test.) + pytest.skip("This test requires `shapely` version 2.1 or later") + + # Test 1: A square containing a triangular hole, and an infinitley thin hole. + square_with_spikes_5x5 = np.array( + ( + (0, 0), + (5, 0), + (5, 0), + (5, 10), # this vertex creates an outward spike and should be removed + (5, 5), + (0, 5 - 1e-13), # this vertex should be rounded to (0, 5) + (3, 3), # this vertex creates an inward spike and should be removed + (0, 5 + 1e-13), # this vertex should be removed because it duplicates (0, 5 - 1e-13) + ) + ) + triangle_empty_tails = np.array(((1, 1), (3, 1), (2, 2), (2.5, 2.5), (0.5, 0.5))) + triangle_collinear = np.array(((4, 2), (3, 3), (2, 4), (4, 2))) # has zero area + # NOTE: Test will fail for self intersecting polys like: ((0,0), (1,1), (2,-1), (3,1), (4,0)) + # Now build a shapely polygon with the 4 small polygons enclosed by big_square_5x5 + exterior_coords = square_with_spikes_5x5 + interior_coords_list = [ + triangle_empty_tails, + triangle_collinear, # this triangle should be eliminated + ] + # Test using a non-empty exterior polygon (big_square_5x5) + orig_polygon = shapely.Polygon(exterior_coords, interior_coords_list) + new_polygon = cleanup_shapely_object(orig_polygon, tolerance_ratio=1e-12) + # Delete any nearby or overlapping vertices (cleanup_shapely_object() does not do this). + new_polygon = shapely.simplify(new_polygon, tolerance=1e-10) + # Now `new_polygon` should only contain the coordinates of the square (with a duplicate at end). + assert len(new_polygon.exterior.coords) == 5 # squares have 4 vertices but shapely adds 1 + assert len(new_polygon.interiors) == 1 # only the "triangle_empty_tails" interior hole survives + assert len(new_polygon.interiors[0].coords) == 4 # triangles have 3 vertices but shapely adds 1 + # Test 2: An infinitely thin triangle exterior with some holes (which should be deleted) + exterior_coords = triangle_collinear # has zero area + orig_polygon = shapely.Polygon(exterior_coords) + new_polygon = cleanup_shapely_object(orig_polygon, tolerance_ratio=1e-12) + new_polygon = shapely.simplify(new_polygon, tolerance=1e-10) + assert len(new_polygon.exterior.coords) == 0 # empty / collinear polygons should get deleted diff --git a/tests/test_components/test_grid.py b/tests/test_components/test_grid.py index 587a09ddbd..e063c38b5a 100644 --- a/tests/test_components/test_grid.py +++ b/tests/test_components/test_grid.py @@ -1,7 +1,10 @@ """Tests grid operations.""" +from __future__ import annotations + import numpy as np import pytest + import tidy3d as td from tidy3d.components.grid.grid import Coords, FieldGrid, Grid from tidy3d.exceptions import SetupError diff --git a/tests/test_components/test_grid_spec.py b/tests/test_components/test_grid_spec.py index 73096b289c..7ac2b7eb71 100644 --- a/tests/test_components/test_grid_spec.py +++ b/tests/test_components/test_grid_spec.py @@ -1,8 +1,11 @@ """Tests GridSpec.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.exceptions import SetupError @@ -41,17 +44,17 @@ def test_make_coords(): def test_make_coords_with_snapping_points(): """Test the behavior of snapping points""" gs = make_grid_spec() - make_coords_args = dict( - structures=[ + make_coords_args = { + "structures": [ td.Structure(geometry=td.Box(size=(2, 2, 1)), medium=td.Medium()), td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.Medium(permittivity=4)), ], - symmetry=(0, 0, 0), - periodic=(False, False, False), - wavelength=1.0, - num_pml_layers=(0, 0), - axis=0, - ) + "symmetry": (0, 0, 0), + "periodic": (False, False, False), + "wavelength": 1.0, + "num_pml_layers": (0, 0), + "axis": 0, + } # 1) no snapping points, 0.85 is not on any grid boundary coord_original = gs.grid_x.make_coords( @@ -83,7 +86,7 @@ def test_make_coords_with_snapping_points(): # 3) snapping takes no effect if it's too close to interval boundaries # forming the simulation boundary coord = gs.grid_x.make_coords( - snapping_points=((0.98, 0, 0),), + snapping_points=((0.98, 0, 0), (-0.98, 0, 0)), **make_coords_args, ) assert np.allclose(coord_original, coord) @@ -541,3 +544,13 @@ def test_uniform_grid_dl_validation(dl, expect_exception): grid_spec=td.GridSpec.uniform(dl=dl), run_time=1e-12, ) + + +def test_custom_grid_boundary_validation(): + """Tests that the 'coords' is at least length 2 and sorted in ascending order.""" + + with pytest.raises(pydantic.ValidationError): + _ = td.CustomGridBoundaries(coords=[10]) + + with pytest.raises(pydantic.ValidationError): + _ = td.CustomGridBoundaries(coords=[9, 10, 9, 10, 11, 9, 8]) diff --git a/tests/test_components/test_heat.py b/tests/test_components/test_heat.py index 24eb3dfdcc..ccf29af9d6 100644 --- a/tests/test_components/test_heat.py +++ b/tests/test_components/test_heat.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import numpy as np import pydantic.v1 as pd import pytest -import tidy3d as td from matplotlib import pyplot as plt + +import tidy3d as td from tidy3d import ( ConvectionBC, DistanceUnstructuredGrid, @@ -11,6 +14,7 @@ HeatFluxBC, HeatSimulation, HeatSimulationData, + HeatSource, MediumMediumInterface, SimulationBoundary, SolidSpec, @@ -20,7 +24,6 @@ TemperatureBC, TemperatureData, TemperatureMonitor, - UniformHeatSource, UniformUnstructuredGrid, ) from tidy3d.exceptions import DataError @@ -40,6 +43,7 @@ def make_heat_mediums(): heat_spec=SolidSpec( capacity=2, conductivity=3, + density=1, ), name="solid_medium", ) @@ -56,6 +60,26 @@ def test_heat_medium(): with pytest.raises(pd.ValidationError): _ = solid_medium.heat_spec.updated_copy(conductivity=-1) + # check we can create solid medium from SI units + solid_from_si = td.SolidMedium.from_si_units( + conductivity=1, + capacity=1, + density=1, + ) + assert solid_from_si.conductivity == 1e-6 + assert solid_from_si.density == 1e-18 + + assert solid_from_si == solid_from_si.heat + + with pytest.raises(ValueError): + _ = solid_from_si.charge + + with pytest.raises(ValueError): + _ = solid_from_si.electrical + + with pytest.raises(ValueError): + _ = solid_from_si.optical + def make_heat_structures(): fluid_medium, solid_medium = make_heat_mediums() @@ -135,7 +159,7 @@ def make_heat_mnt_data(): y = np.linspace(0, 2, ny) z = np.linspace(0, 3, nz) T = np.random.default_rng().uniform(300, 350, (nx, ny, nz)) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} temperature_field = td.SpatialDataArray(T, coords=coords) mnt_data1 = TemperatureData(monitor=temp_mnt1, temperature=temperature_field) @@ -197,7 +221,7 @@ def make_heat_mnt_data(): y = np.linspace(0, 2, ny) z = np.linspace(0, 3, nz) T = np.random.default_rng().uniform(300, 350, (nx, ny, nz)) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} temperature_field = td.SpatialDataArray(T, coords=coords) mnt_data5 = TemperatureData(monitor=temp_mnt5, temperature=temperature_field) @@ -207,7 +231,7 @@ def make_heat_mnt_data(): y = np.linspace(0, 2, ny) z = np.linspace(0, 3, nz) T = np.random.default_rng().uniform(300, 350, (nx, ny, nz)) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} temperature_field = td.SpatialDataArray(T, coords=coords) mnt_data6 = TemperatureData(monitor=temp_mnt6, temperature=temperature_field) @@ -251,20 +275,32 @@ def test_grid_spec(): def make_heat_source(): - return UniformHeatSource(structures=["solid_structure"], rate=100) + return HeatSource(structures=["solid_structure"], rate=100) + + +def make_custom_heat_source(): + return HeatSource( + structures=["solid_structure"], + rate=td.SpatialDataArray( + np.ones((1, 2, 3)), coords={"x": [0], "y": [1, 2], "z": [3, 4, 5]} + ), + ) def test_heat_source(): source = make_heat_source() + source = make_custom_heat_source() with pytest.raises(pd.ValidationError): _ = source.updated_copy(structures=[]) -def make_heat_sim(): +def make_heat_sim(include_custom_source: bool = True): fluid_medium, solid_medium = make_heat_mediums() fluid_structure, solid_structure = make_heat_structures() bc_temp, bc_flux, bc_conv = make_heat_bcs() - heat_source = make_heat_source() + sources = [make_heat_source()] + if include_custom_source: + sources += [make_custom_heat_source()] pl1 = HeatBoundarySpec( condition=bc_conv, placement=MediumMediumInterface(mediums=["fluid_medium", "solid_medium"]) @@ -292,7 +328,7 @@ def make_heat_sim(): size=(2, 2, 2), boundary_spec=[pl1, pl2, pl3, pl4, pl5], grid_spec=grid_spec, - sources=[heat_source], + sources=sources, monitors=temp_mnts, ) @@ -323,7 +359,7 @@ def test_heat_sim(): _ = heat_sim.updated_copy(boundary_spec=[pl]) with pytest.raises(pd.ValidationError): - _ = heat_sim.updated_copy(sources=[UniformHeatSource(structures=["noname"])], rate=-10) + _ = heat_sim.updated_copy(sources=[HeatSource(structures=["noname"])], rate=-10) # run 2D case _ = heat_sim.updated_copy(center=(0.7, 0, 0), size=(0, 2, 2), monitors=heat_sim.monitors[:5]) @@ -379,10 +415,10 @@ def test_heat_sim(): medium=heat_sim.medium, ) with pytest.raises(pd.ValidationError): - _ = heat_sim.updated_copy(structures=list(heat_sim.structures) + [struct_1d]) + _ = heat_sim.updated_copy(structures=[*list(heat_sim.structures), struct_1d]) with pytest.raises(pd.ValidationError): - _ = heat_sim.updated_copy(structures=list(heat_sim.structures) + [struct_2d]) + _ = heat_sim.updated_copy(structures=[*list(heat_sim.structures), struct_2d]) # no data expected inside a monitor for mnt_size in [(0.2, 0.2, 0.2), (0, 1, 1), (0, 2, 0), (0, 0, 0)]: @@ -417,6 +453,14 @@ def place_box(center_offset): ) ], grid_spec=td.UniformUnstructuredGrid(dl=0.1), + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="test_monitor", + unstructured=True, + ) + ], ) # create all permutations of squares being shifted 1, -1, or zero in all three directions @@ -458,6 +502,14 @@ def test_sim_structure_extent(box_size, log_level): placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300) ) ], + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="test_monitor", + unstructured=True, + ) + ], grid_spec=td.UniformUnstructuredGrid(dl=0.1), ) @@ -513,6 +565,14 @@ def test_relative_min_dl_warning(): placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300) ) ], + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="test_monitor", + unstructured=True, + ) + ], ) with AssertLogLevel("WARNING"): @@ -531,6 +591,14 @@ def test_relative_min_dl_warning(): placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300) ) ], + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="test_monitor", + unstructured=True, + ) + ], ) with AssertLogLevel("WARNING"): @@ -549,6 +617,14 @@ def test_relative_min_dl_warning(): placement=td.SimulationBoundary(), condition=td.TemperatureBC(temperature=300) ) ], + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="test_monitor", + unstructured=True, + ) + ], ) @@ -593,7 +669,7 @@ def test_symmetry_expanded(zero_dim_axis): z = np.linspace(*data_span_z, num_points[2]) v = np.sin(x[:, None, None]) * np.cos(y[None, :, None]) * np.exp(z[None, None, :]) - data_cart = td.SpatialDataArray(v, coords=dict(x=x, y=y, z=z)) + data_cart = td.SpatialDataArray(v, coords={"x": x, "y": y, "z": z}) data_ugrid = cartesian_to_unstructured(data_cart, seed=33342) mnt_cart = td.TemperatureMonitor( @@ -622,8 +698,69 @@ def test_symmetry_expanded(zero_dim_axis): data_expanded_cart = mnt_data_cart_expanded.temperature data_expanded_ugrid = mnt_data_ugrid_expanded.temperature - print(data_expanded_ugrid.bounds) - print(mnt_bounds) + # print(data_expanded_ugrid.bounds) + # print(mnt_bounds) assert np.all(data_expanded_ugrid.bounds == mnt_bounds) assert data_expanded_cart.does_cover(mnt_bounds) + + +def test_unsteady_setup(): + """Test that unsteady setup works correctly.""" + + _, solid_medium = make_heat_mediums() + solid_structure = td.Structure( + geometry=td.Box(center=(0, 0, 0), size=(1, 1, 1)), + medium=solid_medium, + name="solid_structure", + ) + + heat_sim = make_heat_sim(include_custom_source=False) + unsteady_spec = td.UnsteadyHeatAnalysis( + initial_temperature=300, unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=100) + ) + + temp_mnt = TemperatureMonitor(size=(1, 1, 1), name="mnt", unstructured=True) + bc = HeatBoundarySpec( + condition=td.TemperatureBC(temperature=300), + placement=StructureBoundary(structure="solid_structure"), + ) + + heat_sim = heat_sim.updated_copy( + structures=[solid_structure], + analysis_spec=unsteady_spec, + monitors=[temp_mnt], + boundary_spec=[bc], + ) + + with pytest.raises(pd.ValidationError): + solid_medium = td.MultiPhysicsMedium( + heat=td.SolidMedium( + conductivity=3, + ), + name="solid_medium", + ) + new_struct = solid_structure.updated_copy(medium=solid_medium) + _ = heat_sim.updated_copy(structures=[new_struct]) + + with pytest.raises(pd.ValidationError): + solid_medium = td.MultiPhysicsMedium( + heat=td.SolidMedium( + conductivity=3, + capacity=2, + ), + name="solid_medium", + ) + new_struct = solid_structure.updated_copy(medium=solid_medium) + _ = heat_sim.updated_copy(structures=[new_struct]) + + with pytest.raises(pd.ValidationError): + solid_medium = td.MultiPhysicsMedium( + heat=td.SolidMedium( + conductivity=3, + density=2, + ), + name="solid_medium", + ) + new_struct = solid_structure.updated_copy(medium=solid_medium) + _ = heat_sim.updated_copy(structures=[new_struct]) diff --git a/tests/test_components/test_heat_charge.py b/tests/test_components/test_heat_charge.py index 4921cd3e29..7044cb7478 100644 --- a/tests/test_components/test_heat_charge.py +++ b/tests/test_components/test_heat_charge.py @@ -1,10 +1,13 @@ """Test suite for heat-charge simulation objects and data using pytest fixtures.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pd import pytest -import tidy3d as td from matplotlib import pyplot as plt + +import tidy3d as td from tidy3d.components.tcad.types import ( AugerRecombination, CaugheyThomasMobility, @@ -98,6 +101,7 @@ def mediums(): charge=td.ChargeConductorMedium( conductivity=1, ), + heat=td.SolidMedium(conductivity=1.1, capacity=1.2, density=2.3), name="solid_medium", ) @@ -130,12 +134,32 @@ def mediums(): name="insulator_medium", ) + semiconductor_medium = td.MultiPhysicsMedium( + optical=td.Medium( + permittivity=5, + conductivity=0.01, + heat_spec=td.SolidSpec( + capacity=2, + conductivity=3, + ), + ), + charge=td.SemiconductorMedium( + N_c=1e10, + N_v=1e10, + E_g=1, + mobility_n=td.ConstantMobilityModel(mu=1500), + mobility_p=td.ConstantMobilityModel(mu=1500), + ), + name="solid_medium", + ) + return { "fluid_medium": fluid_medium, "solid_medium": solid_medium, "solid_no_heat": solid_no_heat, "solid_no_elect": solid_no_elect, "insulator_medium": insulator_medium, + "semiconductor_medium": semiconductor_medium, } @@ -174,12 +198,19 @@ def structures(mediums): name="insulator_structure", ) + semiconductor_structure = td.Structure( + geometry=box, + medium=mediums["semiconductor_medium"], + name="semiconductor_structure", + ) + return { "fluid_structure": fluid_structure, "solid_structure": solid_structure, "solid_struct_no_heat": solid_struct_no_heat, "solid_struct_no_elect": solid_struct_no_elect, "insulator_structure": insulator_structure, + "semiconductor_structure": semiconductor_structure, } @@ -222,18 +253,24 @@ def monitors(): energy_band_mnt1 = td.SteadyEnergyBandMonitor(size=(1.6, 2, 3), name="bandgap_test") + mesh_mnt = td.VolumeMeshMonitor(size=(1.6, 2, 3), name="mesh_test") + + electric_field_mnt = td.SteadyElectricFieldMonitor(size=(1.6, 2, 3), name="electric_field_test") + return [ - temp_mnt1, - temp_mnt2, - temp_mnt3, - temp_mnt4, - volt_mnt1, - volt_mnt2, - volt_mnt3, - volt_mnt4, - capacitance_mnt1, - free_carrier_mnt1, - energy_band_mnt1, + temp_mnt1, # 0 + temp_mnt2, # 1 + temp_mnt3, # 2 + temp_mnt4, # 3 + volt_mnt1, # 4 + volt_mnt2, # 5 + volt_mnt3, # 6 + volt_mnt4, # 7 + capacitance_mnt1, # 8 + free_carrier_mnt1, # 9 + energy_band_mnt1, # 10 + mesh_mnt, # 11 + electric_field_mnt, # 12 ] @@ -333,7 +370,12 @@ def voltage_capacitance_simulation(mediums, structures, boundary_conditions, mon bc_insulating = td.InsulatingBC() pl7 = td.HeatChargeBoundarySpec( condition=bc_insulating, - placement=td.StructureBoundary(structure="solid_structure"), + placement=td.StructureBoundary(structure="semiconductor_structure"), + ) + + # we need two voltage BCs for Charge simulations + pl8 = pl7.updated_copy( + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0)), ) # Let’s pick a couple of monitors. We'll definitely include the CapacitanceMonitor @@ -346,10 +388,10 @@ def voltage_capacitance_simulation(mediums, structures, boundary_conditions, mon # Build a new HeatChargeSimulation voltage_cap_sim = td.HeatChargeSimulation( medium=mediums["insulator_medium"], - structures=[structures["insulator_structure"], structures["solid_structure"]], + structures=[structures["insulator_structure"], structures["semiconductor_structure"]], center=(0, 0, 0), size=(2, 2, 2), - boundary_spec=[pl6, pl7], + boundary_spec=[pl6, pl7, pl8], grid_spec=grid_specs["uniform"], sources=[], monitors=chosen_monitors, @@ -411,7 +453,7 @@ def temperature_monitor_data(monitors): y = np.linspace(0, 2, ny) z = np.linspace(0, 3, nz) T = np.random.default_rng().uniform(300, 350, (nx, ny, nz)) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} temperature_field = td.SpatialDataArray(T, coords=coords) mnt_data1 = td.TemperatureData(monitor=temp_mnt1, temperature=temperature_field) @@ -481,7 +523,10 @@ def temperature_monitor_data(monitors): @pytest.fixture(scope="module") def voltage_monitor_data(monitors): """Creates different voltage monitor data.""" - _, _, _, _, volt_mnt1, volt_mnt2, volt_mnt3, volt_mnt4, _, _, _ = monitors + volt_mnt1 = monitors[4] + volt_mnt2 = monitors[5] + volt_mnt3 = monitors[6] + volt_mnt4 = monitors[7] # SpatialDataArray nx, ny, nz = 9, 6, 5 @@ -489,7 +534,7 @@ def voltage_monitor_data(monitors): y = np.linspace(0, 2, ny) z = np.linspace(0, 3, nz) T = np.random.default_rng().uniform(-5, 5, (nx, ny, nz)) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} voltage_field = td.SpatialDataArray(T, coords=coords) mnt_data1 = td.SteadyPotentialData(monitor=volt_mnt1, potential=voltage_field) @@ -563,6 +608,40 @@ def capacitance_monitor_data(monitors): return (cap_data1,) +@pytest.fixture(scope="module") +def mesh_monitor_data(monitors): + """Creates different voltage monitor data.""" + mesh_mnt = monitors[11] + + # TetrahedralGridDataset + tet_grid_points = td.PointDataArray( + [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + dims=("index", "axis"), + ) + + tet_grid_cells = td.CellDataArray( + [[0, 1, 2, 4], [1, 2, 3, 4]], + dims=("cell_index", "vertex_index"), + ) + + tet_grid_values = td.IndexedDataArray( + np.zeros((tet_grid_points.shape[0],)), + dims=("index",), + name="Mesh", + ) + + tet_grid = td.TetrahedralGridDataset( + points=tet_grid_points, + cells=tet_grid_cells, + values=tet_grid_values, + ) + + # SpatialDataArray + mesh_data = td.VolumeMeshData(monitor=mesh_mnt, mesh=tet_grid) + + return (mesh_data,) + + @pytest.fixture(scope="module") def free_carrier_monitor_data(monitors): """Creates different voltage monitor data.""" @@ -607,6 +686,76 @@ def energy_band_monitor_data(monitors): return (eb_data1,) +@pytest.fixture(scope="module") +def electric_field_monitor_data(monitors): + """Creates different electric field monitor data.""" + monitor = monitors[12] + + # TetrahedralGridDataset + tet_grid_points = td.PointDataArray( + [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + dims=("index", "axis"), + ) + + tet_grid_cells = td.CellDataArray( + [[0, 1, 2, 4], [1, 2, 3, 4]], + dims=("cell_index", "vertex_index"), + ) + + tet_grid_values = td.PointDataArray( + [[0.0, 1.0, 0.0], [1.0, 1.0, 1.0], [3.0, 5.0, 1.0], [4.0, 5.0, 3.0], [5.0, 2.0, 1.0]], + dims=( + "index", + "axis", + ), + name="T", + ) + + tet_grid = td.TetrahedralGridDataset( + points=tet_grid_points, + cells=tet_grid_cells, + values=tet_grid_values, + ) + + mnt_data1 = td.SteadyElectricFieldData(monitor=monitor, E=tet_grid) + + # TriangularGridDataset + tri_grid_points = td.PointDataArray( + [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], + dims=("index", "axis"), + ) + + tri_grid_cells = td.CellDataArray( + [[0, 1, 2], [1, 2, 3]], + dims=("cell_index", "vertex_index"), + ) + + tri_grid_values = td.IndexedFieldVoltageDataArray( + [ + [[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]], + [[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]], + [[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]], + [[1.0, 1.5], [-1.0, 1.1], [5.1, 0.0]], + ], + coords={"index": np.arange(4), "axis": np.arange(3), "voltage": [-1, 1]}, + name="T", + ) + + tri_grid = td.TriangularGridDataset( + normal_axis=1, + normal_pos=0, + points=tri_grid_points, + cells=tri_grid_cells, + values=tri_grid_values, + ) + + mnt_data2 = td.SteadyElectricFieldData(monitor=monitor, E=tri_grid) + + mnt_data3 = td.SteadyElectricFieldData(monitor=monitor, E=None) + + return (mnt_data1, mnt_data2, mnt_data3) + + @pytest.fixture(scope="module") def simulation_data( heat_simulation, @@ -618,6 +767,7 @@ def simulation_data( capacitance_monitor_data, free_carrier_monitor_data, energy_band_monitor_data, + mesh_monitor_data, ): """Creates 'HeatChargeSimulationData' for both Heat and Conduction simulations.""" heat_sim_data = td.HeatChargeSimulationData( @@ -640,7 +790,20 @@ def simulation_data( data=(voltage_monitor_data[0], free_carrier_monitor_data[0]), ) - return [heat_sim_data, cond_sim_data, voltage_capacitance_sim_data, current_voltage_sim_data] + mesh_monitor = mesh_monitor_data[0].monitor + mesh_data = td.VolumeMesherData( + simulation=conduction_simulation, + data=mesh_monitor_data, + monitors=[mesh_monitor], + ) + + return [ + heat_sim_data, + cond_sim_data, + voltage_capacitance_sim_data, + current_voltage_sim_data, + mesh_data, + ] # -------------------------- @@ -711,10 +874,14 @@ def test_heat_charge_bcs_validation(boundary_conditions): with pytest.raises(pd.ValidationError): td.CurrentBC(source=td.DCCurrentSource(current=td.inf)) + with pytest.raises(pd.ValidationError): + td.VoltageBC(source=td.DCVoltageSource(voltage=np.array([td.inf, 0, 1]))) + def test_heat_charge_monitors_validation(monitors): """Checks for no name and negative size in monitors.""" temp_mnt = monitors[0] + mesh_mnt = monitors[11] # Invalid monitor name with pytest.raises(pd.ValidationError): @@ -724,6 +891,10 @@ def test_heat_charge_monitors_validation(monitors): with pytest.raises(pd.ValidationError): temp_mnt.updated_copy(size=(-1, 2, 3)) + # Mesh monitor 1D + with pytest.raises(pd.ValidationError): + mesh_mnt.updated_copy(size=(0, 1, 0)) + def test_monitor_crosses_medium(mediums, structures, heat_simulation, conduction_simulation): """Tests whether monitor crosses structures with relevant material specifications.""" @@ -752,13 +923,59 @@ def test_monitor_crosses_medium(mediums, structures, heat_simulation, conduction medium=solid_no_heat, structures=[solid_struct_no_heat], monitors=[temp_monitor] ) + # check error is raised in voltage monitor doesn't cross a conducting medium + with pytest.raises(pd.ValidationError): + volt_mnt = td.SteadyPotentialMonitor(center=(0, 0, 0), size=(0, td.inf, td.inf)) + _ = conduction_simulation.updated_copy(monitors=[volt_mnt]) + def test_heat_charge_mnt_data( - temperature_monitor_data, voltage_monitor_data, capacitance_monitor_data + temperature_monitor_data, voltage_monitor_data, electric_field_monitor_data ): """Tests whether different heat-charge monitor data can be created.""" assert len(temperature_monitor_data) == 4, "Expected 4 temperature monitor data entries." assert len(voltage_monitor_data) == 4, "Expected 4 voltage monitor data entries." + assert len(electric_field_monitor_data) == 3, "Expected 3 electric field monitor data entries." + + for mnt_data in electric_field_monitor_data: + assert "E" in mnt_data.field_components.keys() + + symm_data = mnt_data.symmetry_expanded_copy + assert symm_data.E == mnt_data.E + + names = mnt_data.field_name("abs^2") + assert names == "E²" + names = mnt_data.field_name() + assert names == "E" + + # make sure an error is raised if we don't use a field data array + # TriangularGridDataset + tri_grid_points = td.PointDataArray( + [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], + dims=("index", "axis"), + ) + + tri_grid_cells = td.CellDataArray( + [[0, 1, 2], [1, 2, 3]], + dims=("cell_index", "vertex_index"), + ) + + tri_grid_values = td.IndexedDataArray( + [1.0, 2.0, 3.0, 4.0], + dims=("index",), + name="T", + ) + + tri_grid = td.TriangularGridDataset( + normal_axis=1, + normal_pos=0, + points=tri_grid_points, + cells=tri_grid_cells, + values=tri_grid_values, + ) + + with pytest.raises(pd.ValidationError): + _ = mnt_data.updated_copy(E=tri_grid) def test_grid_spec_validation(grid_specs): @@ -790,6 +1007,7 @@ def test_device_characteristics(): steady_dc_hole_capacitance=capacitance, steady_dc_electron_capacitance=capacitance, steady_dc_current_voltage=current_voltage, + steady_dc_resistance_voltage=current_voltage, ) @@ -810,9 +1028,13 @@ def test_heat_charge_sources(structures): def test_heat_charge_simulation(simulation_data): """Tests 'HeatChargeSimulation' and 'ConductionSimulation' objects.""" - heat_sim_data, cond_sim_data, voltage_capacitance_sim_data, current_voltage_simulation_data = ( - simulation_data - ) + ( + heat_sim_data, + cond_sim_data, + voltage_capacitance_sim_data, + current_voltage_simulation_data, + mesh_data, + ) = simulation_data # Test Heat Simulation heat_sim = heat_sim_data.simulation @@ -823,19 +1045,22 @@ def test_heat_charge_simulation(simulation_data): assert cond_sim is not None, "Conduction simulation should be created successfully." voltage_capacitance_sim = voltage_capacitance_sim_data.simulation - assert ( - voltage_capacitance_sim is not None - ), "Voltage-Capacitance simulation should be created successfully." + assert voltage_capacitance_sim is not None, ( + "Voltage-Capacitance simulation should be created successfully." + ) current_voltage_sim = current_voltage_simulation_data.simulation - assert ( - current_voltage_sim is not None - ), "Current-Voltage simulation should be created successfully." + assert current_voltage_sim is not None, ( + "Current-Voltage simulation should be created successfully." + ) + + mesher = mesh_data.mesher + assert mesher is not None, "VolumeMesher should be created successfully." def test_sim_data_plotting(simulation_data): """Tests whether simulation data can be plotted and appropriate errors are raised.""" - heat_sim_data, cond_sim_data, cap_sim_data, fc_sim_data = simulation_data + heat_sim_data, cond_sim_data, cap_sim_data, fc_sim_data, mesh_data = simulation_data # Plotting temperature data heat_sim_data.plot_field("test", z=0) @@ -852,7 +1077,7 @@ def test_sim_data_plotting(simulation_data): with pytest.raises(DataError): heat_sim_data.plot_field("empty") - # Test plotting with invalid data + # Test plotting with 3D data with pytest.raises(DataError): heat_sim_data.plot_field("test") @@ -874,6 +1099,64 @@ def test_sim_data_plotting(simulation_data): heat_sim_data.updated_copy(simulation=sim) +def test_mesh_plotting(simulation_data): + """Tests whether mesh can be plotted and appropriate errors are raised.""" + heat_sim_data, cond_sim_data, cap_sim_data, fc_sim_data, mesh_data = simulation_data + + # Plotting mesh from unstructured temperature data + heat_sim_data.plot_mesh("tri") + heat_sim_data.plot_mesh("tet", y=0.5) + + # Plotting mesh from unstructured voltage data + cond_sim_data.plot_mesh("v_tri", structures_fill=False) + cond_sim_data.plot_mesh("v_tet", y=0.5) + + # Plotting mesh from mesh data + mesh_data.plot_mesh("mesh_test", z=0) + + plt.close() + + # Test plotting from structured data + with pytest.raises(DataError): + heat_sim_data.plot_mesh("test") + + # Test plotting with no data + with pytest.raises(DataError): + heat_sim_data.plot_mesh("empty") + + # Test plotting with 3D data + with pytest.raises(DataError): + heat_sim_data.plot_mesh("tet") + + # Test plotting with invalid key + with pytest.raises(KeyError): + heat_sim_data.plot_mesh("test3", x=0) + + # Test plotting with invalid field_name + with pytest.raises(DataError): + mesh_data.plot_mesh("mesh_test", z=0, field_name="wrong") + + +def test_conduction_simulation_has_conductors(conduction_simulation, structures): + """Test whether error is raised if conduction simulation has no conductors.""" + + with pytest.raises(pd.ValidationError): + _ = conduction_simulation.updated_copy( + monitors=[], + structures=[structures["insulator_structure"]], + ) + + +def test_coupling_source(conduction_simulation, heat_simulation): + """Test whether the coupling source can be applied.""" + + with pytest.raises(pd.ValidationError): + _ = conduction_simulation.updated_copy(sources=[td.HeatFromElectricSource()]) + + with pytest.raises(pd.ValidationError): + _ = heat_simulation.updated_copy(sources=[td.HeatFromElectricSource()]) + + # -------------------------- # Test Classes with Fixtures # -------------------------- @@ -1047,11 +1330,17 @@ def test_charge_simulation( ) _ = sim.updated_copy(boundary_spec=[bc_p, new_bc_n]) + # test error is raised when more than one voltage array is provided + with pytest.raises(pd.ValidationError): + new_bc_p = bc_p.updated_copy( + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[1, 2])) + ) + _ = sim.updated_copy(boundary_spec=[new_bc_p, bc_n]) + def test_doping_distributions(self): """Test doping distributions.""" # Implementation needed # This test was empty in the original code. - pass # -------------------------- @@ -1085,6 +1374,13 @@ def place_box(center_offset): ) ], grid_spec=td.UniformUnstructuredGrid(dl=0.1), + monitors=[ + td.SteadyPotentialMonitor( + center=[0, 0, 0], + size=(td.inf, td.inf, td.inf), + name="test_monitor", + ) + ], ) # Create all permutations of squares being shifted 1, -1, or zero in all three directions @@ -1127,6 +1423,11 @@ def test_sim_structure_extent(box_size, log_level): ) ], grid_spec=td.UniformUnstructuredGrid(dl=0.1), + monitors=[ + td.SteadyPotentialMonitor( + center=(0, 0, 0), size=(td.inf, td.inf, td.inf), name="test_monitor" + ) + ], ) @@ -1176,16 +1477,16 @@ def test_gaussian_doping_get_contrib(): coords = {"x": [0], "y": [0], "z": [0]} contrib = box._get_contrib(coords) - assert np.isclose(float(contrib), max_N, rtol=1e-6) + assert np.isclose(contrib.item(), max_N, rtol=1e-6) coords = {"x": [0.5], "y": [0], "z": [0]} contrib = box._get_contrib(coords) - assert np.isclose(float(contrib), min_N, rtol=1e-6) + assert np.isclose(contrib.item(), min_N, rtol=1e-6) coords = {"x": [0.5 - width / 2], "y": [0], "z": [0]} contrib = box._get_contrib(coords) expected_value = max_N * np.exp(-width * width / 4 / box.sigma / box.sigma / 2) - assert np.isclose(float(contrib), expected_value, rtol=1e-6) + assert np.isclose(contrib.item(), expected_value, rtol=1e-6) def test_gaussian_doping_get_contrib_2d_coords(): @@ -1325,7 +1626,7 @@ def test_dynamic_simulation_updates(heat_simulation): # Add a new monitor new_monitor = td.TemperatureMonitor(size=(1, 1, 1), name="new_temp_mnt") updated_sim = heat_simulation.updated_copy( - monitors=tuple(list(heat_simulation.monitors) + [new_monitor]) + monitors=(*list(heat_simulation.monitors), new_monitor) ) assert len(updated_sim.monitors) == len(heat_simulation.monitors) + 1 assert updated_sim.monitors[-1].name == "new_temp_mnt" @@ -1333,7 +1634,7 @@ def test_dynamic_simulation_updates(heat_simulation): def test_plotting_functions(simulation_data): """Test plotting functions with various data.""" - heat_sim_data, cond_sim_data, cap_sim_data, fc_sim_data = simulation_data + heat_sim_data, cond_sim_data, cap_sim_data, fc_sim_data, mesh_data = simulation_data # Valid plotting try: @@ -1366,13 +1667,13 @@ def test_bandgap_monitor(): tri_grid_values_single_voltage = td.IndexedVoltageDataArray( [[0.0], [0], [3], [3]], - coords=dict(index=np.arange(4), voltage=[1]), + coords={"index": np.arange(4), "voltage": [1]}, name="test", ) tri_grid_values_multi_voltage = td.IndexedVoltageDataArray( [[0.0, 0.0], [0, 0], [3, -3], [3, -3]], - coords=dict(index=np.arange(4), voltage=[-1, 1]), + coords={"index": np.arange(4), "voltage": [-1, 1]}, name="test", ) @@ -1414,7 +1715,7 @@ def test_bandgap_monitor(): tet_grid_values_single_voltage = td.IndexedVoltageDataArray( [[0.0], [0.0], [0.0], [0.0], [3.0], [3.0], [3.0], [3.0]], - coords=dict(index=np.arange(8), voltage=[1]), + coords={"index": np.arange(8), "voltage": [1]}, name="test_tet", ) @@ -1429,7 +1730,7 @@ def test_bandgap_monitor(): [3.0, 3.5], [3.0, 3.5], ], - coords=dict(index=np.arange(8), voltage=[-1, 1]), + coords={"index": np.arange(8), "voltage": [-1, 1]}, name="test_tet", ) @@ -1599,3 +1900,143 @@ def test_symmetry_capacitance(symmetry): assert ( mnt_data.symmetry_expanded_copy.electron_capacitance.data[n] == data[n] * scaling_factor ) + + +def test_unsteady_parameters(): + """Test that unsteady parameters are set correctly.""" + + _ = td.UnsteadyHeatAnalysis( + initial_temperature=300, + unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=1), + ) + + # test non-positive initial temperature raises error + with pytest.raises(pd.ValidationError): + _ = td.UnsteadyHeatAnalysis( + initial_temperature=0, + unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=1), + ) + + # test negative time step raises error + with pytest.raises(pd.ValidationError): + _ = td.UnsteadyHeatAnalysis( + initial_temperature=10, + unsteady_spec=td.UnsteadySpec(time_step=-0.1, total_time_steps=1), + ) + + # test negative total time steps raises error + with pytest.raises(pd.ValidationError): + _ = td.UnsteadyHeatAnalysis( + initial_temperature=10, + unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=-1), + ) + + +def test_unsteady_heat_analysis(heat_simulation): + """Test that the validators for unsteady heat analysis are working.""" + + unsteady_analysis_spec = td.UnsteadyHeatAnalysis( + initial_temperature=300, + unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=1), + ) + + temp_mnt = td.TemperatureMonitor( + center=(0, 0, 0), + size=(td.inf, td.inf, td.inf), + name="temperature", + unstructured=True, + interval=2, + ) + + # this should work since the monitor is unstructured + unsteady_sim = heat_simulation.updated_copy( + analysis_spec=unsteady_analysis_spec, monitors=[temp_mnt] + ) + + with pytest.raises(pd.ValidationError): + temp_mnt = temp_mnt.updated_copy(unstructured=False) + _ = unsteady_sim.updated_copy(monitors=[temp_mnt]) + + with pytest.raises(pd.ValidationError): + temp_mnt = temp_mnt.updated_copy(unstructured=True, interval=0) + _ = unsteady_sim.updated_copy(monitors=[temp_mnt]) + + # try simulation with excessive time steps + with pytest.raises(pd.ValidationError): + mew_spex = td.UnsteadyHeatAnalysis( + initial_temperature=300, + unsteady_spec=td.UnsteadySpec(time_step=0.1, total_time_steps=100000), + ) + _ = unsteady_sim.updated_copy(analysis_spec=mew_spex) + + +def test_heat_conduction_simulations(): + """Test that heat-conduction simulations have necessary components.""" + + # let's create some mediums + solid_medium = td.MultiPhysicsMedium( + heat=td.SolidSpec(conductivity=1), + charge=td.ChargeConductorMedium(conductivity=1), + name="solid_medium", + ) + air = td.MultiPhysicsMedium(heat=td.FluidSpec(), charge=td.ChargeInsulatorMedium(), name="air") + + struct1 = td.Structure( + geometry=td.Box(center=(0, 0, 0), size=(1, 1, 1)), + medium=solid_medium, + name="struct1", + ) + + # thermal BC + thermal_bc = td.HeatChargeBoundarySpec( + condition=td.TemperatureBC(temperature=300), + placement=td.StructureBoundary(structure="struct1"), + ) + + # electric BCs + electric_bc = td.HeatChargeBoundarySpec( + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[1])), + placement=td.StructureBoundary(structure="struct1"), + ) + + # thermal monitors + temp_monitor = td.TemperatureMonitor( + center=(0, 0, 0), size=(1, 1, 1), name="temp_monitor", unstructured=True + ) + # electric monitors + voltage_monitor = td.SteadyPotentialMonitor( + center=(0, 0, 0), size=(1, 1, 1), name="voltage_monitor", unstructured=True + ) + + sim = td.HeatChargeSimulation( + medium=air, + structures=[struct1], + center=(0, 0, 0), + size=(3, 3, 3), + boundary_spec=[thermal_bc, electric_bc], + grid_spec=td.UniformUnstructuredGrid(dl=0.1), + sources=[], + monitors=[temp_monitor, voltage_monitor], + ) + + with pytest.raises(pd.ValidationError): + # no thermal monitors + _ = sim.updated_copy(monitors=[voltage_monitor]) + + with pytest.raises(pd.ValidationError): + # voltage array in electric BC + _ = sim.updated_copy( + boundary_spec=[ + thermal_bc, + electric_bc.updated_copy( + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[1, 2])) + ), + ] + ) + + # this doesn't raise error + coupling_sim = sim.updated_copy(sources=[td.HeatFromElectricSource()]) + + with pytest.raises(pd.ValidationError): + # This should error since the conduction simulation doesn't have a monitor + _ = sim.updated_copy(monitors=[temp_monitor]) diff --git a/tests/test_components/test_layerrefinement.py b/tests/test_components/test_layerrefinement.py index f5185f381c..506234ee01 100644 --- a/tests/test_components/test_layerrefinement.py +++ b/tests/test_components/test_layerrefinement.py @@ -1,8 +1,11 @@ """Tests 2d corner finder.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.grid.corner_finder import CornerFinderSpec from tidy3d.components.grid.grid_spec import GridRefinement, LayerRefinementSpec @@ -285,7 +288,8 @@ def count_grids_within_layer(sim_t): ) -def test_corner_refinement_outside_domain(): +@pytest.mark.parametrize("gap_meshing_iters", [0, 1]) +def test_corner_refinement_outside_domain(gap_meshing_iters): """Test the behavior of corner refinement if corners are outside the simulation domain.""" # CPW waveguides that goes through the simulation domain along x-axis, so that the corners @@ -313,6 +317,7 @@ def test_corner_refinement_outside_domain(): axis=2, corner_refinement=td.GridRefinement(refinement_factor=5), refinement_inside_sim_only=True, + gap_meshing_iters=gap_meshing_iters, ) sim = td.Simulation( @@ -333,9 +338,466 @@ def count_grids_within_gap(sim_t): return len(y) # just 2 grids sampling the gap - assert count_grids_within_gap(sim) == 2 + assert count_grids_within_gap(sim) == gap_meshing_iters + 2 # 2) refined if corners outside simulation domain is accounted for. layer = layer.updated_copy(refinement_inside_sim_only=False) sim = sim.updated_copy(grid_spec=td.GridSpec.auto(wavelength=1, layer_refinement_specs=[layer])) + assert count_grids_within_gap(sim) > 2 + + +def test_dl_min_from_smallest_feature(): + structure = td.Structure( + geometry=td.PolySlab( + vertices=[ + [0, 0], + [2, 0], + [2, 1], + [1, 1], + [1, 1.1], + [2, 1.1], + [2, 2], + [1, 2], + [1, 2.2], + [0.7, 2.2], + [0.7, 2], + [0, 2], + ], + slab_bounds=[-1, 1], + axis=2, + ), + medium=td.PECMedium(), + ) + + # check expected dl_min + layer_spec = td.LayerRefinementSpec( + axis=2, + size=(td.inf, td.inf, 2), + corner_finder=td.CornerFinderSpec( + convex_resolution=10, + ), + ) + dl_min = layer_spec._dl_min_from_smallest_feature([structure]) + assert np.allclose(0.3 / 10, dl_min) + + layer_spec = td.LayerRefinementSpec( + axis=2, + size=(td.inf, td.inf, 2), + corner_finder=td.CornerFinderSpec(mixed_resolution=10), + ) + dl_min = layer_spec._dl_min_from_smallest_feature([structure]) + assert np.allclose(0.2 / 10, dl_min) + + layer_spec = td.LayerRefinementSpec( + axis=2, + size=(td.inf, td.inf, 2), + corner_finder=td.CornerFinderSpec( + concave_resolution=10, + ), + ) + dl_min = layer_spec._dl_min_from_smallest_feature([structure]) + assert np.allclose(0.1 / 10, dl_min) + + # check grid is generated succesfully + sim = td.Simulation( + size=(5, 5, 5), + structures=[structure], + grid_spec=td.GridSpec.auto(layer_refinement_specs=[layer_spec], wavelength=100 * td.C_0), + run_time=1e-20, + ) + + _ = sim.grid + + +def test_gap_meshing(): + w = 1 + length = 10 + + l_shape_1 = td.Structure( + medium=td.PECMedium(), + geometry=td.PolySlab( + axis=2, + slab_bounds=[0, 2], + vertices=[ + [0, 0], + [length, 0], + [length, w], + [w, w], + [w, length], + [0, length], + ], + ), + ) + + gap = 0.1 + l_shape_2 = td.Structure( + medium=td.PECMedium(), + geometry=td.PolySlab( + axis=2, + slab_bounds=[0, 2], + vertices=[ + [w + gap, w + gap], + [w + gap + length, w + gap], + [w + gap + length, w + gap + w], + [w + gap + w, w + gap + w], + [w + gap + w, w + gap + length], + [w + gap, w + gap + length], + [0, w + gap + length], + [0, gap + length], + [w + gap, gap + length], + ], + ), + ) + + # ax = l_shape_1.plot(z=1) + # l_shape_2.plot(z=1, ax=ax) + + for num_iters in range(2): + grid_spec = td.GridSpec( + grid_x=td.AutoGrid(min_steps_per_wvl=10), + grid_y=td.AutoGrid(min_steps_per_wvl=10), + grid_z=td.AutoGrid(min_steps_per_wvl=10), + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=2, + corner_finder=None, + gap_meshing_iters=num_iters, + size=[td.inf, td.inf, 2], + center=[0, 0, 1], + ) + ], + wavelength=7, + ) + + sim = td.Simulation( + structures=[l_shape_1, l_shape_2], + grid_spec=grid_spec, + size=(1.2 * length, 1.2 * length, 2), + center=(0.5 * length, 0.5 * length, 0), + run_time=1e-15, + ) + + # ax = sim.plot(z=1) + # sim.plot_grid(z=1, ax=ax) + # ax.set_xlim([0, 2]) + # ax.set_ylim([0, 2]) + + resolved_x = np.any( + np.logical_and(sim.grid.boundaries.x > w, sim.grid.boundaries.x < w + gap) + ) + resolved_y = np.any( + np.logical_and(sim.grid.boundaries.y > w, sim.grid.boundaries.y < w + gap) + ) + + if num_iters == 0: + assert (not resolved_x) and (not resolved_y) + else: + assert resolved_x and resolved_y + + # test ingored small feature + sim_size = (1, 1, 1) + box = td.Structure( + geometry=td.Box(size=(0.95, 0.2, 0.95)), + medium=td.PECMedium(), + ) + + reentry_gap = td.Structure( + geometry=td.PolySlab( + slab_bounds=[-0.2, 0.2], axis=1, vertices=[(-0.3, 0.52), (-0.05, 0.3), (0.2, 0.52)] + ), + medium=td.Medium(), + ) + + aux = td.Structure( + geometry=td.Box(center=(0.0, 0, 0.5), size=(2, 0.4, 0.23)), + medium=td.Medium(), + ) + + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.periodic(), + y=td.Boundary.periodic(), + z=td.Boundary.periodic(), + ), + structures=[box, reentry_gap, aux], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(td.inf, 0.2, td.inf), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + assert not any( + np.isclose(sim.grid.boundaries.x, reentry_gap.geometry.bounding_box.center[0], rtol=1e-2) + ) + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(y=0, ax=ax) + # sim.plot_grid(y=0, ax=ax) + # plt.show() + + # test internal polygon + + gap_z = td.Structure( + geometry=td.Box(center=(0.3, 0, 0.1), size=(0.05, 0.4, 0.5)), + medium=td.Medium(), + ) + + gap_x = td.Structure( + geometry=td.Box(center=(0.03, 0, 0.07), size=(0.3, 0.4, 0.05)), + medium=td.Medium(), + ) + + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.periodic(), + y=td.Boundary.periodic(), + z=td.Boundary.periodic(), + ), + structures=[box, gap_x, gap_z], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(td.inf, 0.2, td.inf), + corner_finder=None, + gap_meshing_iters=2, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + assert any(np.isclose(sim.grid.boundaries.x, gap_z.geometry.center[0], atol=1e-4)) + assert any(np.isclose(sim.grid.boundaries.z, gap_x.geometry.center[2], atol=1e-4)) + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(y=0, ax=ax) + # sim.plot_grid(y=0, ax=ax) + # plt.show() + + # test gaps near pec/pmc + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.pec(), + y=td.Boundary.pml(), + z=td.Boundary.pmc(), + ), + structures=[box], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(td.inf, 0.2, td.inf), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + expected_grid_line = box.geometry.size[0] / 2 + (sim_size[0] - box.geometry.size[0]) / 4 + assert any(np.isclose(sim.grid.boundaries.x, expected_grid_line)) + assert any(np.isclose(sim.grid.boundaries.x, -expected_grid_line)) + + expected_grid_line = box.geometry.size[2] / 2 + (sim_size[2] - box.geometry.size[2]) / 4 + assert any(np.isclose(sim.grid.boundaries.z, expected_grid_line)) + assert any(np.isclose(sim.grid.boundaries.z, -expected_grid_line)) + + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(y=0, ax=ax) + # sim.plot_grid(y=0, ax=ax) + # plt.show() + + # test limited size of layer spec + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.pec(), + y=td.Boundary.pml(), + z=td.Boundary.pmc(), + ), + structures=[box], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(0.5, 0.2, 0.5), + center=(0.5, 0, -0.5), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + expected_grid_line = box.geometry.size[0] / 2 + (sim_size[0] - box.geometry.size[0]) / 4 + assert any(np.isclose(sim.grid.boundaries.x, expected_grid_line)) + assert not any(np.isclose(sim.grid.boundaries.x, -expected_grid_line, atol=1e-2)) + + expected_grid_line = box.geometry.size[2] / 2 + (sim_size[2] - box.geometry.size[2]) / 4 + assert not any(np.isclose(sim.grid.boundaries.z, expected_grid_line, atol=1e-2)) + assert any(np.isclose(sim.grid.boundaries.z, -expected_grid_line)) + + # pretty much zero size layer spec + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.pec(), + y=td.Boundary.pml(), + z=td.Boundary.pmc(), + ), + structures=[box], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(0.05, 0.2, 0.05), + center=(0.05, 0, 0.05), + corner_finder=None, + gap_meshing_iters=2, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + expected_grid_line = box.geometry.size[0] / 2 + (sim_size[0] - box.geometry.size[0]) / 4 + assert not any(np.isclose(sim.grid.boundaries.x, expected_grid_line)) + assert not any(np.isclose(sim.grid.boundaries.x, -expected_grid_line, atol=1e-2)) + + expected_grid_line = box.geometry.size[2] / 2 + (sim_size[2] - box.geometry.size[2]) / 4 + assert not any(np.isclose(sim.grid.boundaries.z, expected_grid_line, atol=1e-2)) + assert not any(np.isclose(sim.grid.boundaries.z, -expected_grid_line)) + + # layer spec is outside + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.pec(), + y=td.Boundary.pml(), + z=td.Boundary.pmc(), + ), + structures=[box], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(0.01, 0.2, 0.01), + center=(10.0, 0, 10.0), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + expected_grid_line = box.geometry.size[0] / 2 + (sim_size[0] - box.geometry.size[0]) / 4 + assert not any(np.isclose(sim.grid.boundaries.x, expected_grid_line)) + assert not any(np.isclose(sim.grid.boundaries.x, -expected_grid_line, atol=1e-2)) + + expected_grid_line = box.geometry.size[2] / 2 + (sim_size[2] - box.geometry.size[2]) / 4 + assert not any(np.isclose(sim.grid.boundaries.z, expected_grid_line, atol=1e-2)) + assert not any(np.isclose(sim.grid.boundaries.z, -expected_grid_line)) + + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(y=0, ax=ax) + # sim.plot_grid(y=0, ax=ax) + # plt.show() + + # test gap near periodic + sim = td.Simulation( + size=sim_size, + center=(0.025, -0.25, 0), + boundary_spec=td.BoundarySpec( + x=td.Boundary.periodic(), + y=td.Boundary.pec(), + z=td.Boundary.periodic(), + ), + structures=[box], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=1, + size=(td.inf, 0.2, td.inf), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(y=0, ax=ax) + # sim.plot_grid(y=0, ax=ax) + # plt.show() + + assert any(np.isclose(sim.grid.boundaries.x, 0.5, atol=1e-4)) + assert any(np.isclose(sim.grid.boundaries.z, -0.5, atol=1e-4)) + + # test a thin strip near periodic + strip = td.Structure( + geometry=td.Box(center=(0, 0.5, 0), size=(0.2, 0.05, 0.6)), + medium=td.PECMedium(), + ) + + sim = td.Simulation( + size=sim_size, + boundary_spec=td.BoundarySpec( + x=td.Boundary.pec(), + y=td.Boundary.periodic(), + z=td.Boundary.pmc(), + ), + structures=[strip], + grid_spec=td.GridSpec.auto( + layer_refinement_specs=[ + td.LayerRefinementSpec( + axis=0, + size=(0.2, td.inf, td.inf), + corner_finder=None, + gap_meshing_iters=1, + dl_min_from_gap_width=True, + ) + ], + min_steps_per_wvl=10, + wavelength=1, + ), + run_time=1e-15, + ) + + assert any(np.isclose(sim.grid.boundaries.y, strip.geometry.center[1], atol=1e-4)) + # _, ax = plt.subplots(1, 1, figsize=(10, 10)) + # sim.plot(x=0, ax=ax) + # sim.plot_grid(x=0, ax=ax) + # plt.show() diff --git a/tests/test_components/test_lumped_element.py b/tests/test_components/test_lumped_element.py index f91ece5b0c..fb15221366 100644 --- a/tests/test_components/test_lumped_element.py +++ b/tests/test_components/test_lumped_element.py @@ -1,8 +1,11 @@ """Tests lumped elements.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.lumped_element import NetworkConversions diff --git a/tests/test_components/test_medium.py b/tests/test_components/test_medium.py index 59a2dd2d34..d6066c4b56 100644 --- a/tests/test_components/test_medium.py +++ b/tests/test_components/test_medium.py @@ -1,11 +1,12 @@ """Tests mediums.""" -from typing import Dict +from __future__ import annotations import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.exceptions import SetupError, ValidationError @@ -14,12 +15,13 @@ MEDIUM = td.Medium() ANIS_MEDIUM = td.AnisotropicMedium(xx=MEDIUM, yy=MEDIUM, zz=MEDIUM) PEC = td.PECMedium() +PMC = td.PMCMedium() PR = td.PoleResidue(poles=[(-1 + 1j, 2 + 2j)]) SM = td.Sellmeier(coeffs=[(1, 2)]) LZ = td.Lorentz(coeffs=[(1, 2, 3)]) DR = td.Drude(coeffs=[(1, 2)]) DB = td.Debye(coeffs=[(1, 2)]) -MEDIUMS = [MEDIUM, ANIS_MEDIUM, PEC, PR, SM, LZ, DR, DB] +MEDIUMS = [MEDIUM, ANIS_MEDIUM, PEC, PR, SM, LZ, DR, DB, PMC] f, AX = plt.subplots() @@ -141,6 +143,10 @@ def test_PEC(): _ = td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.PEC) +def test_PMC(): + _ = td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.PMC) + + def test_lossy_metal(): # frequency_range shouldn't be None with pytest.raises(pydantic.ValidationError): @@ -174,6 +180,11 @@ def test_lossy_metal(): model = mat.scaled_surface_impedance_model num_poles = mat.num_poles + # thickness + mat = td.LossyMetalMedium(conductivity=1.0, frequency_range=(1e14, 4e14), thickness=0.1) + model = mat.scaled_surface_impedance_model + num_poles = mat.num_poles + def test_lossy_metal_surface_roughness(): mat_orig = td.LossyMetalMedium( @@ -287,7 +298,7 @@ def test_sellmeier_from_dispersion(): assert np.allclose(-dn_df * td.C_0 / wvl**2, dn_dwvl) -def eps_compare(medium: td.Medium, expected: Dict, tol: float = 1e-5): +def eps_compare(medium: td.Medium, expected: dict, tol: float = 1e-5): for freq, val in expected.items(): assert np.abs(medium.eps_model(freq) - val) < tol @@ -400,6 +411,8 @@ def test_n_cfl(): assert material.n_cfl == 2 # PEC assert PEC.n_cfl == 1 + # PMC + assert PMC.n_cfl == 1 # anisotropic material = td.AnisotropicMedium(xx=MEDIUM, yy=td.Medium(permittivity=4), zz=MEDIUM) assert material.n_cfl == 1 @@ -828,7 +841,7 @@ def test_custom_medium(): Z = [0] freqs = [2e14] n_data = np.ones((Nx, Ny, Nz, Nf)) - n_dataset = td.ScalarFieldDataArray(n_data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + n_dataset = td.ScalarFieldDataArray(n_data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) def create_mediums(n_dataset): ## Three equivalent ways of defining custom medium for the lens @@ -837,7 +850,9 @@ def create_mediums(n_dataset): _ = td.CustomMedium.from_nk(n_dataset, interp_method="nearest") # define custom medium with permittivity data - eps_dataset = td.ScalarFieldDataArray(n_dataset**2, coords=dict(x=X, y=Y, z=Z, f=freqs)) + eps_dataset = td.ScalarFieldDataArray( + n_dataset**2, coords={"x": X, "y": Y, "z": Z, "f": freqs} + ) _ = td.CustomMedium.from_eps_raw(eps_dataset, interp_method="nearest") # define each component of permittivity via "PermittivityDataset" @@ -851,9 +866,9 @@ def create_mediums(n_dataset): with pytest.raises(pydantic.ValidationError): # repeat some entries so data cannot be interpolated - X2 = [X[0]] + list(X) + X2 = [X[0], *list(X)] n_data2 = np.vstack((n_data[0, :, :, :].reshape(1, Ny, Nz, Nf), n_data)) - n_dataset2 = td.ScalarFieldDataArray(n_data2, coords=dict(x=X2, y=Y, z=Z, f=freqs)) + n_dataset2 = td.ScalarFieldDataArray(n_data2, coords={"x": X2, "y": Y, "z": Z, "f": freqs}) create_mediums(n_dataset=n_dataset2) diff --git a/tests/test_components/test_meshgenerate.py b/tests/test_components/test_meshgenerate.py index 6b10e11a9a..2a5ec3d59f 100644 --- a/tests/test_components/test_meshgenerate.py +++ b/tests/test_components/test_meshgenerate.py @@ -1,9 +1,12 @@ """Tests generating meshes.""" +from __future__ import annotations + import warnings import numpy as np import pytest + import tidy3d as td from tidy3d.components.grid.mesher import GradedMesher from tidy3d.constants import fp_eps @@ -735,7 +738,7 @@ def test_anisotropic_material_meshing(unstructured, z): ), ) - coords = dict(x=[0, 1], y=[0, 1], z=z) + coords = {"x": [0, 1], "y": [0, 1], "z": z} ones = td.SpatialDataArray(np.ones((2, 2, len(z))), coords=coords) if unstructured: ones = cartesian_to_unstructured(ones, seed=951) @@ -815,9 +818,9 @@ def test_override_are_box(): dl=[1, 2, 3], ) - assert isinstance( - override_not_box.geometry, td.Box - ), "Sphere override structure was not converted to Box" + assert isinstance(override_not_box.geometry, td.Box), ( + "Sphere override structure was not converted to Box" + ) def test_override_unshadowed(): diff --git a/tests/test_components/test_microwave.py b/tests/test_components/test_microwave.py index a0cd365791..5fb08815e9 100644 --- a/tests/test_components/test_microwave.py +++ b/tests/test_components/test_microwave.py @@ -1,10 +1,13 @@ """Tests microwave tools.""" +from __future__ import annotations + from math import isclose import numpy as np import pytest import xarray as xr + from tidy3d.components.data.monitor_data import FreqDataArray from tidy3d.components.microwave.data.monitor_data import AntennaMetricsData from tidy3d.components.microwave.formulas.circuit_parameters import ( diff --git a/tests/test_components/test_mode.py b/tests/test_components/test_mode.py index df08f470a3..764a823696 100644 --- a/tests/test_components/test_mode.py +++ b/tests/test_components/test_mode.py @@ -1,10 +1,13 @@ """Tests mode objects.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td from matplotlib import pyplot as plt + +import tidy3d as td from tidy3d.exceptions import SetupError, ValidationError from ..test_data.test_data_arrays import ( @@ -75,21 +78,97 @@ def test_angle_rotation_with_phi(): td.ModeSpec(angle_phi=np.pi / 3, angle_rotation=True) +def test_validation_from_simulation(): + """Test that a ModeSolver created from a simulation ModeMonitor validates correctly.""" + + sim = td.Simulation( + size=(10, 10, 10), + grid_spec=td.GridSpec(wavelength=1.0), + structures=[], + run_time=1e-12, + monitors=[], + ) + + reg_geometry = td.Structure( + geometry=td.Box.from_bounds((-100, -1, -100), (100, 1, 0)), + medium=td.Medium(permittivity=4.0, conductivity=1e-4), + ) + + inf_geometry = td.Structure( + geometry=td.Box.from_bounds((-td.inf, -1, -100), (td.inf, 1, 0)), + medium=td.Medium(permittivity=4.0, conductivity=1e-4), + ) + + anisotropic_geometry = td.Structure( + geometry=td.Box.from_bounds((-1, -1, -100), (1, 1, 0)), + medium=td.AnisotropicMedium( + xx=td.Medium(permittivity=4.0, conductivity=1e-4), + yy=td.Medium(permittivity=4.0, conductivity=1e-4), + zz=td.Medium(permittivity=3.0, conductivity=1e-4), + ), + ) + + rot_monitor = td.ModeMonitor( + size=(0, 5, 5), + name="mode_solver", + mode_spec=td.ModeSpec(angle_rotation=True, angle_theta=np.pi / 4), + freqs=[td.C_0], + ) + + rot_source = td.ModeSource( + size=(0, 5, 5), + mode_spec=td.ModeSpec(angle_rotation=True, angle_theta=np.pi / 4), + source_time=td.GaussianPulse(freq0=td.C_0, fwidth=td.C_0 / 10), + direction="+", + ) + + # First test that a mode object can be added if there's no problem with the geometries + _ = sim.updated_copy(structures=[reg_geometry], monitors=[rot_monitor]) + + # Test that transforming a geometry with an infinite extent raises an error + with pytest.raises(SetupError): + sim.updated_copy(structures=[inf_geometry], monitors=[rot_monitor]) + + # Test that transforming an anisotropic medium raises an error + with pytest.raises(SetupError): + sim.updated_copy(structures=[anisotropic_geometry], monitors=[rot_monitor]) + + # Same thing with a ModeSource + with pytest.raises(SetupError): + sim.updated_copy(structures=[inf_geometry], sources=[rot_source]) + + with pytest.raises(SetupError): + sim.updated_copy(structures=[anisotropic_geometry], sources=[rot_source]) + + # Same thing with ModeSimulation + with pytest.raises(SetupError): + td.ModeSimulation( + structures=[inf_geometry], + size=(0, 5, 5), + mode_spec=td.ModeSpec(angle_rotation=True, angle_theta=np.pi / 4), + freqs=[td.C_0], + ) + + with pytest.raises(SetupError): + td.ModeSimulation( + structures=[anisotropic_geometry], + size=(0, 5, 5), + mode_spec=td.ModeSpec(angle_rotation=True, angle_theta=np.pi / 4), + freqs=[td.C_0], + ) + + def get_mode_sim(): mode_spec = MODE_SPEC.updated_copy(filter_pol="tm") permittivity_monitor = td.PermittivityMonitor( size=(1, 1, 0), center=(0, 0, 0), name="eps", freqs=FS ) - boundary_spec = td.BoundarySpec( - x=td.Boundary.pml(), y=td.Boundary.periodic(), z=td.Boundary.pml() - ) sim = td.ModeSimulation( size=SIZE_2D, freqs=FS, mode_spec=mode_spec, grid_spec=td.GridSpec.auto(wavelength=td.C_0 / FS[0]), monitors=[permittivity_monitor], - boundary_spec=boundary_spec, ) return sim @@ -97,6 +176,8 @@ def get_mode_sim(): def test_mode_sim(): with AssertLogLevel(None): sim = get_mode_sim() + _ = sim.plot(ax=AX) + _ = sim.plot(ax=AX, fill_structures=False, hlim=(-1, 1), vlim=(-1, 1)) _ = sim.plot(y=0, ax=AX) _ = sim.plot_mode_plane(ax=AX) _ = sim.plot_eps_mode_plane(ax=AX) @@ -125,9 +206,14 @@ def test_mode_sim(): with AssertLogLevel("INFO"): _ = sim.updated_copy(freqs=FS[0], grid_spec=grid_spec) # multiple freqs are ok - _ = sim.updated_copy(grid_spec=td.GridSpec.uniform(dl=0.2), freqs=[1e10] + list(sim.freqs)) _ = sim.updated_copy( - size=sim.size, freqs=list(sim.freqs) + [1e10], grid_spec=grid_spec, mode_spec=MODE_SPEC + grid_spec=td.GridSpec.uniform(dl=0.2), freqs=[10000000000.0, *list(sim.freqs)] + ) + _ = sim.updated_copy( + size=sim.size, + freqs=[*list(sim.freqs), 10000000000.0], + grid_spec=grid_spec, + mode_spec=MODE_SPEC, ) # size limit @@ -244,3 +330,54 @@ def get_mode_sim_data(): def test_mode_sim_data(): sim_data = get_mode_sim_data() _ = sim_data.plot_field("Ey", ax=AX, mode_index=0, f=FS[0]) + + +def test_plane_crosses_symmetry_plane_warning(monkeypatch): + """Test that a warning is issued if the mode plane crosses a symmetry plane but the centers do not match.""" + + # Simulation with symmetry in x (axis 0), center at (0, 0, 0) + sim_center = (0, 0, 0) + sim_size = (10, 5, 5) + sim_symmetry = (1, 0, 0) # symmetry in x + + # Plane crosses x=0 (symmetry plane), but plane center != sim center + plane_center = (2, 0, 0) + plane_size = (5, 0, 5) + plane = td.Box(center=plane_center, size=plane_size) + + # Should warn + with AssertLogLevel("WARNING"): + _ = td.ModeSimulation( + center=sim_center, + size=sim_size, + symmetry=sim_symmetry, + plane=plane, + mode_spec=td.ModeSpec(), + freqs=[td.C_0], + ) + + # Now, plane center matches sim center: should NOT warn + plane_center2 = (0, 0, 0) + plane2 = td.Box(center=plane_center2, size=plane_size) + with AssertLogLevel("INFO"): + _ = td.ModeSimulation( + center=sim_center, + size=sim_size, + symmetry=sim_symmetry, + plane=plane2, + mode_spec=td.ModeSpec(), + freqs=[td.C_0], + ) + + # Plane does NOT cross symmetry plane: should NOT warn + plane_center3 = (5, 0, 0) + plane3 = td.Box(center=plane_center3, size=plane_size) + with AssertLogLevel("INFO"): + _ = td.ModeSimulation( + center=sim_center, + size=sim_size, + symmetry=sim_symmetry, + plane=plane3, + mode_spec=td.ModeSpec(), + freqs=[td.C_0], + ) diff --git a/tests/test_components/test_monitor.py b/tests/test_components/test_monitor.py index 825949aef9..aec3cf9ea3 100644 --- a/tests/test_components/test_monitor.py +++ b/tests/test_components/test_monitor.py @@ -1,8 +1,11 @@ """Tests monitors.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.exceptions import SetupError, ValidationError @@ -306,7 +309,7 @@ def test_mode_bend_radius(): size=(5, 0, 1), freqs=np.linspace(1e14, 2e14, 100), name="test", - mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=1), + mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=2), ) _ = td.Simulation( size=(2, 2, 2), diff --git a/tests/test_components/test_packaging.py b/tests/test_components/test_packaging.py index 71d9893224..4f1153acfe 100644 --- a/tests/test_components/test_packaging.py +++ b/tests/test_components/test_packaging.py @@ -1,5 +1,14 @@ +from __future__ import annotations + import pytest -from tidy3d.packaging import Tidy3dImportError, check_import, verify_packages_import + +from tidy3d.packaging import ( + Tidy3dImportError, + check_import, + supports_local_subpixel, + tidy3d_extras, + verify_packages_import, +) assert check_import("tidy3d") is True @@ -62,5 +71,19 @@ def test_check_import(): assert mock_check_import("module2") is False +def test_tidy3d_extras(): + import importlib + + has_tidy3d_extras = importlib.util.find_spec("tidy3d_extras") is not None + print(f"has_tidy3d_extras = {has_tidy3d_extras}") + + @supports_local_subpixel + def get_eps(): + assert tidy3d_extras["use_local_subpixel"] is False + assert tidy3d_extras["mod"] is None + + get_eps() + + if __name__ == "__main__": pytest.main() diff --git a/tests/test_components/test_parameter_perturbation.py b/tests/test_components/test_parameter_perturbation.py index 91f43e93dc..4fbd5d2091 100644 --- a/tests/test_components/test_parameter_perturbation.py +++ b/tests/test_components/test_parameter_perturbation.py @@ -1,16 +1,23 @@ """Tests parameter perturbations.""" +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from ..utils import AssertLogLevel, cartesian_to_unstructured -sp_arr = td.SpatialDataArray(300 * np.ones((2, 2, 2)), coords=dict(x=[1, 2], y=[3, 4], z=[5, 6])) +sp_arr = td.SpatialDataArray( + 300 * np.ones((2, 2, 2)), coords={"x": [1, 2], "y": [3, 4], "z": [5, 6]} +) sp_arr_u = cartesian_to_unstructured(sp_arr) -sp_arr_2d = td.SpatialDataArray(300 * np.ones((2, 1, 2)), coords=dict(x=[1, 2], y=[3.5], z=[5, 6])) +sp_arr_2d = td.SpatialDataArray( + 300 * np.ones((2, 1, 2)), coords={"x": [1, 2], "y": [3.5], "z": [5, 6]} +) sp_arr_2d_u = cartesian_to_unstructured(sp_arr_2d) sp_arrs = [sp_arr, sp_arr_u, sp_arr_2d, sp_arr_2d_u] @@ -77,7 +84,7 @@ def test_heat_perturbation(): _ = perturb.plot(temperature=np.linspace(200, 400, 10), val="angle") # test custom heat perturbation - perturb_data = td.HeatDataArray([1 + 1j, 3 + 1j, 1j], coords=dict(T=[200, 300, 400])) + perturb_data = td.HeatDataArray([1 + 1j, 3 + 1j, 1j], coords={"T": [200, 300, 400]}) for interp_method in ["linear", "nearest"]: perturb = td.CustomHeatPerturbation( @@ -257,7 +264,7 @@ def test_sample(perturb): # test custom charge perturbation perturb_data = td.ChargeDataArray( [[1 + 1j, 3 + 1j, 1j], [2 + 2j, 2j, 2 + 2j]], - coords=dict(n=[2e17, 2e18], p=[1e16, 1e17, 1e18]), + coords={"n": [2e17, 2e18], "p": [1e16, 1e17, 1e18]}, ) for interp_method in ["linear", "nearest"]: @@ -369,13 +376,13 @@ def test_parameter_perturbation(unstructured): perturb_data = td.ChargeDataArray( [[1 + 1j, 3 + 1j, 1j], [2 + 2j, 2j, 2 + 2j]], - coords=dict(n=[2e17, 2e18], p=[1e16, 1e17, 1e18]), + coords={"n": [2e17, 2e18], "p": [1e16, 1e17, 1e18]}, ) charge = td.CustomChargePerturbation(perturbation_values=perturb_data, interp_method="linear") - coords = dict(x=[1, 2], y=[3, 4], z=[5, 6]) - coords2 = dict(x=[1, 2], y=[3, 4], z=[5]) + coords = {"x": [1, 2], "y": [3, 4], "z": [5, 6]} + coords2 = {"x": [1, 2], "y": [3, 4], "z": [5]} temperature = td.SpatialDataArray(300 * np.random.random((2, 2, 2)), coords=coords) electron_density = td.SpatialDataArray(1e18 * np.random.random((2, 2, 2)), coords=coords) hole_density = td.SpatialDataArray(2e18 * np.random.random((2, 2, 2)), coords=coords) @@ -440,9 +447,9 @@ def test_permittivity_perturbation(): hole_range=[0, 2e19], ) - t_arr = td.SpatialDataArray([[[350]]], coords=dict(x=[0], y=[0], z=[0])) - n_arr = td.SpatialDataArray([[[1e18]]], coords=dict(x=[0], y=[0], z=[0])) - p_arr = td.SpatialDataArray([[[2e18]]], coords=dict(x=[0], y=[0], z=[0])) + t_arr = td.SpatialDataArray([[[350]]], coords={"x": [0], "y": [0], "z": [0]}) + n_arr = td.SpatialDataArray([[[1e18]]], coords={"x": [0], "y": [0], "z": [0]}) + p_arr = td.SpatialDataArray([[[2e18]]], coords={"x": [0], "y": [0], "z": [0]}) # basic make perm_pb = td.PermittivityPerturbation(delta_eps=td.ParameterPerturbation(heat=heat_pb)) @@ -533,9 +540,9 @@ def test_index_perturbation(): freq0 = td.C_0 - t_arr = td.SpatialDataArray([[[350]]], coords=dict(x=[0], y=[0], z=[0])) - n_arr = td.SpatialDataArray([[[1e18]]], coords=dict(x=[0], y=[0], z=[0])) - p_arr = td.SpatialDataArray([[[2e18]]], coords=dict(x=[0], y=[0], z=[0])) + t_arr = td.SpatialDataArray([[[350]]], coords={"x": [0], "y": [0], "z": [0]}) + n_arr = td.SpatialDataArray([[[1e18]]], coords={"x": [0], "y": [0], "z": [0]}) + p_arr = td.SpatialDataArray([[[2e18]]], coords={"x": [0], "y": [0], "z": [0]}) # basic make index_pb = td.IndexPerturbation(delta_n=td.ParameterPerturbation(heat=heat_pb), freq=freq0) @@ -663,14 +670,15 @@ def test_delta_model(): freq = td.C_0 / wvl delta_model = td.NedeljkovicSorefMashanovich(ref_freq=freq) + # make sure it serializes + delta_model.json() + # make sure it's interpolating correctly coeffs_3_5 = np.array([3.10e-21, 1.210, 6.05e-20, 1.145, 6.95e-21, 0.986, 9.28e-18, 0.834]) coeffs_4 = np.array([7.4e-22, 1.245, 5.43e-20, 1.153, 7.25e-21, 0.991, 9.99e-18, 0.839]) averaged_vals = (coeffs_3_5 + coeffs_4) / 2 - interpolated_results = [ - value.item() for _, value in delta_model._coeffs_at_ref_freq.data_vars.items() - ] + interpolated_results = [v.item() for v in delta_model._coeffs_at_ref_freq.data.flat] error = np.abs(np.mean(averaged_vals - np.array(interpolated_results))) assert error < 1e-16 diff --git a/tests/test_components/test_perturbation_medium.py b/tests/test_components/test_perturbation_medium.py index eff3063b06..2eec5b4bad 100644 --- a/tests/test_components/test_perturbation_medium.py +++ b/tests/test_components/test_perturbation_medium.py @@ -1,8 +1,11 @@ """Tests mediums.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from ..utils import AssertLogLevel, cartesian_to_unstructured @@ -11,7 +14,7 @@ @pytest.mark.parametrize("unstructured", [False, True]) def test_perturbation_medium(unstructured): # fields to sample at - coords = dict(x=[1, 2], y=[3, 4], z=[5, 6]) + coords = {"x": [1, 2], "y": [3, 4], "z": [5, 6]} temperature = td.SpatialDataArray(300 * np.ones((2, 2, 2)), coords=coords) electron_density = td.SpatialDataArray(1e18 * np.ones((2, 2, 2)), coords=coords) hole_density = td.SpatialDataArray(2e18 * np.ones((2, 2, 2)), coords=coords) @@ -297,7 +300,7 @@ def test_correct_values(dispersive): ), ) - t_arr = td.SpatialDataArray([[[333]]], coords=dict(x=[0], y=[0], z=[0])) + t_arr = td.SpatialDataArray([[[333]]], coords={"x": [0], "y": [0], "z": [0]}) pp_large_sampled = pp_large.apply_data(temperature=t_arr).values[0, 0, 0] pp_small_sampled = pp_small.apply_data(temperature=t_arr).values[0, 0, 0] diff --git a/tests/test_components/test_scene.py b/tests/test_components/test_scene.py index 6f74bd6df3..0704b9cdc6 100644 --- a/tests/test_components/test_scene.py +++ b/tests/test_components/test_scene.py @@ -1,9 +1,12 @@ """Tests the scene and its validators.""" +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pd import pytest + import tidy3d as td from tidy3d.components.scene import MAX_GEOMETRY_COUNT, MAX_NUM_MEDIUMS @@ -113,7 +116,7 @@ def test_structure_alpha(): new_structs = [ td.Structure(geometry=s.geometry, medium=SCENE_FULL.medium) for s in SCENE_FULL.structures ] - S2 = SCENE_FULL.copy(update=dict(structures=new_structs)) + S2 = SCENE_FULL.copy(update={"structures": new_structs}) _ = S2.plot_structures_eps(x=0, alpha=0.5) plt.close() @@ -236,7 +239,7 @@ def test_perturbed_mediums_copy(unstructured, z): ), ) - coords = dict(x=[1, 2], y=[3, 4], z=z) + coords = {"x": [1, 2], "y": [3, 4], "z": z} temperature = td.SpatialDataArray(300 * np.ones((2, 2, len(z))), coords=coords) electron_density = td.SpatialDataArray(1e18 * np.ones((2, 2, len(z))), coords=coords) hole_density = td.SpatialDataArray(2e18 * np.ones((2, 2, len(z))), coords=coords) @@ -307,3 +310,48 @@ def test_max_geometry_validation(): ] with pytest.raises(pd.ValidationError, match=f" {MAX_GEOMETRY_COUNT + 2} "): _ = td.Scene(structures=not_fine) + + +def test_structure_manual_priority(): + """make sure structure is properly orderd based on the priority settings.""" + + box = td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)), + medium=td.Medium(permittivity=2.0), + ) + structures = [] + priorities = [2, 4, -1, -4, 0] + for priority in priorities: + structures.append(box.updated_copy(priority=priority)) + scene = td.Scene( + structures=structures, + ) + + sorted_priorities = [s.priority for s in scene.sorted_structures] + assert all(np.diff(sorted_priorities) >= 0) + + +def test_structure_automatic_priority(): + """make sure metallic structure has the highest priority in `conductor` mode.""" + + box = td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)), + medium=td.Medium(permittivity=2.0), + ) + box_pec = box.updated_copy(medium=td.PEC) + box_lossymetal = box.updated_copy( + medium=td.LossyMetalMedium(conductivity=1.0, frequency_range=(1e14, 2e14)) + ) + structures = [box_pec, box_lossymetal, box] + scene = td.Scene( + structures=structures, + structure_priority_mode="equal", + ) + + # in equal mode, the order is preserved + scene.sorted_structures == structures + + # conductor mode + scene = scene.updated_copy(structure_priority_mode="conductor") + assert scene.sorted_structures[-1].medium == td.PEC + assert isinstance(scene.sorted_structures[-2].medium, td.LossyMetalMedium) diff --git a/tests/test_components/test_sidewall.py b/tests/test_components/test_sidewall.py index f6f735eded..31252a603e 100644 --- a/tests/test_components/test_sidewall.py +++ b/tests/test_components/test_sidewall.py @@ -1,10 +1,13 @@ """test slanted polyslab can be correctly setup and visualized.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td from shapely import Point, Polygon + +import tidy3d as td from tidy3d.constants import fp_eps np.random.seed(4) diff --git a/tests/test_components/test_simulation.py b/tests/test_components/test_simulation.py index c827e648fd..6b82ae5a3d 100644 --- a/tests/test_components/test_simulation.py +++ b/tests/test_components/test_simulation.py @@ -1,5 +1,7 @@ """Tests the simulation and its validators.""" +from __future__ import annotations + import uuid import gdstk @@ -7,8 +9,9 @@ import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td from matplotlib.testing.compare import compare_images + +import tidy3d as td from tidy3d.components import simulation from tidy3d.components.scene import MAX_GEOMETRY_COUNT, MAX_NUM_MEDIUMS from tidy3d.components.simulation import MAX_NUM_SOURCES @@ -560,16 +563,19 @@ def test_validate_zero_dim_boundaries(): pol_angle=0.0, ) - with pytest.raises(pydantic.ValidationError): - td.Simulation( - size=(1, 1, 0), - run_time=1e-12, - sources=[src], - boundary_spec=td.BoundarySpec( - x=td.Boundary.periodic(), - y=td.Boundary.periodic(), - z=td.Boundary.pml(), - ), + with AssertLogLevel("WARNING", contains_str="Periodic"): + assert ( + td.Simulation( + size=(1, 1, 0), + run_time=1e-12, + sources=[src], + boundary_spec=td.BoundarySpec( + x=td.Boundary.periodic(), + y=td.Boundary.periodic(), + z=td.Boundary.pml(), + ), + ).boundary_spec.z + == td.Boundary.periodic() ) # zero-dim simulation with an absorbing boundary any other direction should not error @@ -631,21 +637,21 @@ def test_sources_edge_case_validation(): def test_validate_size_run_time(monkeypatch): monkeypatch.setattr(simulation, "MAX_TIME_STEPS", 1) with pytest.raises(SetupError): - s = SIM.copy(update=dict(run_time=1e-12)) + s = SIM.copy(update={"run_time": 1e-12}) s._validate_size() def test_validate_size_spatial_and_time(monkeypatch): monkeypatch.setattr(simulation, "MAX_CELLS_TIMES_STEPS", 1) with pytest.raises(SetupError): - s = SIM.copy(update=dict(run_time=1e-12)) + s = SIM.copy(update={"run_time": 1e-12}) s._validate_size() def test_validate_mnt_size(monkeypatch): # warning for monitor size monkeypatch.setattr(simulation, "WARN_MONITOR_DATA_SIZE_GB", 1 / 2**30) - s = SIM.copy(update=dict(monitors=(td.FieldMonitor(name="f", freqs=[1e12], size=(1, 1, 1)),))) + s = SIM.copy(update={"monitors": (td.FieldMonitor(name="f", freqs=[1e12], size=(1, 1, 1)),)}) with AssertLogLevel("WARNING"): s._validate_monitor_size() @@ -653,7 +659,7 @@ def test_validate_mnt_size(monkeypatch): monkeypatch.setattr(simulation, "MAX_SIMULATION_DATA_SIZE_GB", 1 / 2**30) with pytest.raises(SetupError): s = SIM.copy( - update=dict(monitors=(td.FieldMonitor(name="f", freqs=[1e12], size=(1, 1, 1)),)) + update={"monitors": (td.FieldMonitor(name="f", freqs=[1e12], size=(1, 1, 1)),)} ) s._validate_monitor_size() @@ -746,7 +752,7 @@ def medium_customani(self): x = np.linspace(-1, 1, Nx) y = np.linspace(-1, 1, Ny) z = np.linspace(-1, 1, Nz) - coords = dict(x=x, y=y, z=z) + coords = {"x": x, "y": y, "z": z} permittivity = td.SpatialDataArray(2 * np.ones((Nx, Ny, Nz)), coords=coords) conductivity = td.SpatialDataArray(np.ones((Nx, Ny, Nz)), coords=coords) medium_xx = td.CustomMedium(permittivity=permittivity, conductivity=conductivity) @@ -765,7 +771,7 @@ def medium_customani(self): r = 1 n_data[r_mesh <= r] = n0 * (1 - A * r_mesh[r_mesh <= r] ** 2) # convert to dataset array - n_dataset = td.SpatialDataArray(n_data, coords=dict(x=x, y=y, z=z)) + n_dataset = td.SpatialDataArray(n_data, coords={"x": x, "y": y, "z": z}) medium_zz = td.CustomMedium.from_nk(n_dataset, interp_method="nearest") return td.CustomAnisotropicMedium(xx=medium_xx, yy=medium_yy, zz=medium_zz) @@ -819,10 +825,7 @@ def test_bad_eps_arg(self, eps_comp): @pytest.mark.parametrize( "eps_comp", - [ - None, - ] - + diag_comps, + [None, *diag_comps], ) def test_plot_anisotropic_medium(self, eps_comp): """Test plotting diagonal components of a diagonally anisotropic medium succeeds or not. @@ -853,11 +856,7 @@ def test_plot_anisotropic_medium_diff(self, tmp_path, eps_comp1, eps_comp2, expe @pytest.mark.parametrize( "eps_comp", - [ - None, - ] - + diag_comps - + offdiag_comps, + [None, *diag_comps, *offdiag_comps], ) def test_plot_fully_anisotropic_medium(self, eps_comp): """Test plotting all components of a fully anisotropic medium. @@ -884,10 +883,7 @@ def test_plot_fully_anisotropic_medium_diff(self, tmp_path, eps_comp1, eps_comp2 @pytest.mark.parametrize( "eps_comp", - [ - None, - ] - + diag_comps, + [None, *diag_comps], ) def test_plot_customanisotropic_medium(self, eps_comp, medium_customani): """Test plotting diagonal components of a diagonally anisotropic custom medium. @@ -970,7 +966,7 @@ def test_structure_alpha(): new_structs = [ td.Structure(geometry=s.geometry, medium=SIM_FULL.medium) for s in SIM_FULL.structures ] - S2 = SIM_FULL.copy(update=dict(structures=new_structs)) + S2 = SIM_FULL.copy(update={"structures": new_structs}) _ = S2.plot_structures_eps(x=0, alpha=0.5) plt.close() @@ -1012,7 +1008,7 @@ def test_plot_eps_with_default_frequency(): def test_plot_symmetries(): - S2 = SIM.copy(update=dict(symmetry=(1, 0, -1))) + S2 = SIM.copy(update={"symmetry": (1, 0, -1)}) S2.plot_symmetries(x=0) plt.close() @@ -1020,7 +1016,7 @@ def test_plot_symmetries(): def test_plot_grid(): override = td.Structure(geometry=td.Box(size=(1, 1, 1)), medium=td.Medium()) S2 = SIM_FULL.copy( - update=dict(grid_spec=td.GridSpec(wavelength=1.0, override_structures=[override])) + update={"grid_spec": td.GridSpec(wavelength=1.0, override_structures=[override])} ) S2.plot_grid(x=0) plt.close() @@ -1035,7 +1031,7 @@ def test_plot_boundaries(): ), z=td.Boundary(plus=td.Periodic(), minus=td.Periodic()), ) - S2 = SIM_FULL.copy(update=dict(boundary_spec=bound_spec)) + S2 = SIM_FULL.copy(update={"boundary_spec": bound_spec}) S2.plot_boundaries(z=0) plt.close() @@ -1063,25 +1059,25 @@ def test_complex_fields(): ), z=td.Boundary(plus=td.Periodic(), minus=td.Periodic()), ) - S2 = SIM_FULL.copy(update=dict(boundary_spec=bound_spec)) + S2 = SIM_FULL.copy(update={"boundary_spec": bound_spec}) assert S2.complex_fields def test_nyquist(): S = SIM.copy( - update=dict( - sources=( + update={ + "sources": ( td.PointDipole( polarization="Ex", source_time=td.GaussianPulse(freq0=2e14, fwidth=1e11) ), ), - ) + } ) assert S.nyquist_step > 1 # nyquist step decreses to 1 when the frequency-domain monitor is at high frequency S_MONITOR = S.copy( - update=dict(monitors=[td.FluxMonitor(size=(1, 1, 0), freqs=[1e14, 1e20], name="flux")]) + update={"monitors": [td.FluxMonitor(size=(1, 1, 0), freqs=[1e14, 1e20], name="flux")]} ) assert S_MONITOR.nyquist_step == 1 @@ -1104,15 +1100,15 @@ def test_discretize_non_intersect(): def test_warn_sim_background_medium_freq_range(): with AssertLogLevel("WARNING"): _ = SIM.copy( - update=dict( - sources=( + update={ + "sources": ( td.PointDipole( polarization="Ex", source_time=td.GaussianPulse(freq0=2e14, fwidth=1e11) ), ), - monitors=(td.FluxMonitor(name="test", freqs=[2e12], size=(1, 1, 0)),), - medium=td.Medium(frequency_range=(0, 1e12)), - ) + "monitors": (td.FluxMonitor(name="test", freqs=[2e12], size=(1, 1, 0)),), + "medium": td.Medium(frequency_range=(0, 1e12)), + } ) @@ -1415,49 +1411,49 @@ def test_proj_monitor_distance(): # Cartesian monitor projecting backwards ( td.FieldProjectionCartesianMonitor, - dict(x=[4], y=[5], proj_distance=-1e5, proj_axis=2), + {"x": [4], "y": [5], "proj_distance": -1e5, "proj_axis": 2}, None, "+", ), # Cartesian monitor with custom origin projecting backwards ( td.FieldProjectionCartesianMonitor, - dict(x=[4], y=[5], proj_distance=39, proj_axis=2), + {"x": [4], "y": [5], "proj_distance": 39, "proj_axis": 2}, (1, 2, -40), "+", ), # Cartesian monitor with custom origin projecting backwards with normal_dir '-' ( td.FieldProjectionCartesianMonitor, - dict(x=[4], y=[5], proj_distance=41, proj_axis=2), + {"x": [4], "y": [5], "proj_distance": 41, "proj_axis": 2}, (1, 2, -40), "-", ), # Angle monitor projecting backwards ( td.FieldProjectionAngleMonitor, - dict(theta=[np.pi / 2 + 1e-2], phi=[0], proj_distance=1e3), + {"theta": [np.pi / 2 + 1e-2], "phi": [0], "proj_distance": 1e3}, None, "+", ), # Angle monitor projecting backwards with custom origin ( td.FieldProjectionAngleMonitor, - dict(theta=[np.pi / 2 - 0.02], phi=[0], proj_distance=10), + {"theta": [np.pi / 2 - 0.02], "phi": [0], "proj_distance": 10}, (0, 0, -0.5), "+", ), # Angle monitor projecting backwards with custom origin and normal_dir '-' ( td.FieldProjectionAngleMonitor, - dict(theta=[np.pi / 2 + 0.02], phi=[0], proj_distance=10), + {"theta": [np.pi / 2 + 0.02], "phi": [0], "proj_distance": 10}, (0, 0, 0.5), "-", ), # Cartesian monitor using approximations but too short proj_distance ( td.FieldProjectionCartesianMonitor, - dict(x=[4], y=[5], proj_distance=9, proj_axis=2), + {"x": [4], "y": [5], "proj_distance": 9, "proj_axis": 2}, None, "+", ), @@ -1604,6 +1600,25 @@ def test_warn_lumped_elements_outside_sim_bounds(): ) assert len(sim_good.volumetric_structures) == 1 + # Lumped element is touching the boundary along one of its nonzero dims + resistor_in = td.LumpedResistor( + size=(0.5, 1, 0), + center=(0, 0.5, 0), + voltage_axis=1, + resistance=50, + name="resistor_touching", + ) + with AssertLogLevel("INFO"): + sim_good = td.Simulation( + size=sim_size, + center=sim_center, + sources=[src], + run_time=1e-12, + lumped_elements=[resistor_in], + boundary_spec=td.BoundarySpec.all_sides(boundary=td.Periodic()), + ) + assert len(sim_good.volumetric_structures) == 1 + # Lumped element outside - should emit warning and not be added resistor_out = td.LumpedResistor( size=(0.5, 1, 0), @@ -1616,16 +1631,16 @@ def test_warn_lumped_elements_outside_sim_bounds(): sim_bad = sim_good.updated_copy(lumped_elements=[resistor_out]) assert len(sim_bad.volumetric_structures) == 0 - # Lumped element extends to boundary and is not strictly inside simulation + # Lumped element is flush against boundary along its zero size dimension resistor_edge = td.LumpedResistor( size=(0.5, 1, 0), - center=(0, 0.5, 0), + center=(0, 0.5, 1), voltage_axis=1, resistance=50, name="resistor_edge", ) with AssertLogLevel("WARNING"): - _ = sim_good.updated_copy(lumped_elements=[resistor_edge]) + sim_bad = sim_good.updated_copy(lumped_elements=[resistor_edge]) assert len(sim_bad.volumetric_structures) == 0 @@ -2085,7 +2100,9 @@ def test_tfsf_structures_grid(): Y = np.linspace(-1, 1, Ny) Z = np.linspace(-1, 1, Nz) data = np.ones((Nx, Ny, Nz, 1)) - eps_diagonal_data = td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=[td.C_0])) + eps_diagonal_data = td.ScalarFieldDataArray( + data, coords={"x": X, "y": Y, "z": Z, "f": [td.C_0]} + ) eps_components = {f"eps_{d}{d}": eps_diagonal_data for d in "xyz"} eps_dataset = td.PermittivityDataset(**eps_components) custom_medium = td.CustomMedium(eps_dataset=eps_dataset, name="my_medium") @@ -2334,7 +2351,7 @@ def test_dt(): geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), medium=td.PoleResidue(eps_inf=0.16, poles=[(-1 + 1j, 2 + 2j)]), ) - sim_new = sim.copy(update=dict(structures=[structure])) + sim_new = sim.copy(update={"structures": [structure]}) assert sim_new.dt == 0.4 * dt @@ -2368,6 +2385,27 @@ def test_conformal_dt(): assert sim_heuristic.dt == dt +def test_edge_correction(): + """make sure edge correction can be enabled for PEC and lossy meal.""" + sim = td.Simulation( + size=(2.0, 2.0, 2.0), + run_time=1e-12, + structures=[], + grid_spec=td.GridSpec.uniform(dl=0.1), + subpixel=td.SubpixelSpec( + pec=td.PECConformal(edge_singularity_correction=False), + lossy_metal=td.SurfaceImpedance(edge_singularity_correction=False), + ), + ) + + sim = sim.updated_copy( + subpixel=td.SubpixelSpec( + pec=td.PECConformal(edge_singularity_correction=True), + lossy_metal=td.SurfaceImpedance(edge_singularity_correction=True), + ) + ) + + def test_sim_volumetric_structures(tmp_path): """Test volumetric equivalent of 2D materials.""" sigma = 0.45 @@ -2651,7 +2689,7 @@ def test_perturbed_mediums_copy(unstructured, z): ), ) - coords = dict(x=[1, 2], y=[3, 4], z=z) + coords = {"x": [1, 2], "y": [3, 4], "z": z} temperature = td.SpatialDataArray(300 * np.ones((2, 2, len(z))), coords=coords) electron_density = td.SpatialDataArray(1e18 * np.ones((2, 2, len(z))), coords=coords) hole_density = td.SpatialDataArray(2e18 * np.ones((2, 2, len(z))), coords=coords) @@ -2819,11 +2857,11 @@ def test_sim_subsection(unstructured, nz): perm = td.SpatialDataArray( 1 + np.random.random((11, 12, nz)), - coords=dict( - x=np.linspace(-0.51, 0.52, 11), - y=np.linspace(-1.02, 1.04, 12), - z=np.linspace(-1.51, 1.51, nz), - ), + coords={ + "x": np.linspace(-0.51, 0.52, 11), + "y": np.linspace(-1.02, 1.04, 12), + "z": np.linspace(-1.51, 1.51, nz), + }, ) if unstructured: @@ -3075,7 +3113,9 @@ def test_advanced_material_intersection(): Y = np.linspace(-1, 1, Ny) Z = np.linspace(-1, 1, Nz) data = np.ones((Nx, Ny, Nz, 1)) - eps_diagonal_data = td.ScalarFieldDataArray(data, coords=dict(x=X, y=Y, z=Z, f=[td.C_0])) + eps_diagonal_data = td.ScalarFieldDataArray( + data, coords={"x": X, "y": Y, "z": Z, "f": [td.C_0]} + ) eps_components = {f"eps_{d}{d}": eps_diagonal_data for d in "xyz"} eps_dataset = td.PermittivityDataset(**eps_components) custom_medium = td.CustomMedium(eps_dataset=eps_dataset, name="my_medium") @@ -3566,3 +3606,108 @@ def test_sim_volumetric_structures_with_lumped_elements(tmp_path): vol_structures = sim.volumetric_structures assert len(vol_structures) == 2 assert np.isclose(vol_structures[1].geometry.bounding_box.size[0], 0, rtol=RTOL) + + +def test_create_sim_multiphysics(): + s = td.Simulation( + run_time=1e-12, + size=(10, 10, 10), + grid_spec=td.GridSpec(wavelength=1.0), + medium=td.Medium(permittivity=1.0), + structures=[ + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0.5, 0.5)), + medium=td.MultiPhysicsMedium( + optical=td.Medium(permittivity=2.0), + charge=td.ChargeInsulatorMedium(permittivity=2), + name="SiO2", + ), + ), + ], + ) + + +def test_create_sim_multiphysics_with_incompatibilities(): + modulated = td.Medium( + permittivity=2, + modulation_spec=td.ModulationSpec( + permittivity=td.SpaceTimeModulation( + time_modulation=td.ContinuousWaveTimeModulation(freq0=1e12, amplitude=1.1, phase=0), + ) + ), + ) + assert modulated._has_incompatibilities + + nonlinear = td.Medium( + nonlinear_spec=td.NonlinearSpec( + models=[ + td.NonlinearSusceptibility(chi3=1.5), + td.TwoPhotonAbsorption(beta=1, sigma=1, tau=1, e_e=1, e_h=0.8, c_e=1, c_h=1), + td.KerrNonlinearity(n2=1), + ], + num_iters=20, + ) + ) + with pytest.raises(pydantic.ValidationError): + s = td.Simulation( + run_time=1e-12, + size=(10, 10, 10), + grid_spec=td.GridSpec(wavelength=1.0), + medium=td.Medium(permittivity=1.0), + structures=[ + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0.5, 0.5)), + medium=nonlinear, + ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0.5, 0.5)), + medium=td.MultiPhysicsMedium( + optical=modulated, + charge=td.ChargeInsulatorMedium(permittivity=2), + name="SiO2", + ), + ), + ], + ) + + +def test_messages_contain_object_names(): + """Make sure that errors and warnings contain the name of the object.""" + # Note: This function currently tests for out-of-bounds errors and warnings. + # Create an empty simulation. + sim = td.Simulation( + size=(1, 1, 1), + grid_spec=td.GridSpec.auto(wavelength=4), + run_time=1e-12, + ) + + # Test 1) Create a structure lying outside the simulation boundary. + # Check that a warning message is generated containing the structure's `name`. + name = "structure_123" + structure = td.Structure( + name=name, + geometry=td.Box(center=(1.0, 0.0, 0.0), size=(0.5, 0.5, 0.5)), + medium=td.Medium(permittivity=2.0), + ) + with AssertLogLevel("WARNING", contains_str=name): + _ = sim.updated_copy(structures=[structure]) + + # Test 2) Create a source lying outside the simulation boundary. + # Check that an error message is generated containing the source's `name`. + name = "source_123" + source = td.UniformCurrentSource( + name=name, + center=(0, -1.0, 0), + size=(1, 0, 0.5), + polarization="Ex", + source_time=td.GaussianPulse(freq0=100e14, fwidth=10e14), + ) + with pytest.raises(pydantic.ValidationError, match=name) as e: + _ = sim.updated_copy(sources=[source]) + + # Test 3) Create a monitor lying outside the simulation boundary. + # Check that an error message is generated containing the monitor's `name`. + name = "monitor_123" + monitor = td.FieldMonitor(name=name, center=(-1.0, 0, 0), size=(0.5, 0, 1), freqs=[100e14]) + with pytest.raises(pydantic.ValidationError, match=name) as e: + _ = sim.updated_copy(monitors=[monitor]) diff --git a/tests/test_components/test_source.py b/tests/test_components/test_source.py index b3817d57dc..b39a1686d2 100644 --- a/tests/test_components/test_source.py +++ b/tests/test_components/test_source.py @@ -1,9 +1,12 @@ """Tests sources.""" +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.source.field import CHEB_GRID_WIDTH, DirectionalSource from tidy3d.exceptions import SetupError @@ -145,6 +148,67 @@ def test_dipole(): _ = td.PointDipole(size=(1, 1, 1), source_time=g, center=(1, 2, 3), polarization="Ex") +def test_dipole_sources_from_angles(): + g = td.GaussianPulse(freq0=1e12, fwidth=0.1e12) + + with pytest.raises(pydantic.ValidationError): + _ = td.PointDipole.sources_from_angles( + size=(1, 1, 1), + source_time=g, + center=(1, 2, 3), + angle_theta=np.pi / 4, + angle_phi=np.pi / 4, + ) + + with pytest.raises(ValueError): + _ = td.PointDipole.sources_from_angles( + source_time=g, + angle_theta=np.pi / 4, + angle_phi=np.pi / 4, + component="invalid", + center=(1, 2, 3), + ) + + assert ( + len( + td.PointDipole.sources_from_angles( + source_time=g, + angle_theta=np.pi / 4, + angle_phi=np.pi / 4, + component="electric", + center=(1, 2, 3), + ) + ) + == 3 + ) + + assert ( + len( + td.PointDipole.sources_from_angles( + source_time=g, + angle_theta=np.pi / 4, + angle_phi=np.pi / 2, + component="electric", + center=(1, 2, 3), + ) + ) + == 2 + ) + + assert ( + len( + td.PointDipole.sources_from_angles( + source_time=g, + angle_theta=np.pi / 2, + angle_phi=np.pi / 2, + component="electric", + center=(1, 2, 3), + ) + ) + == 1 + ) + + def test_FieldSource(): g = td.GaussianPulse(freq0=1e12, fwidth=0.1e12) mode_spec = td.ModeSpec(num_modes=2) @@ -369,7 +433,7 @@ def test_custom_source_time(): _ = cst.amp_time(-1) assert np.allclose(cst.amp_time([2]), np.exp(-1j * 2 * np.pi * 2 * freq0), rtol=0, atol=ATOL) - vals = td.components.data.data_array.TimeDataArray([1, 2], coords=dict(t=[-1, -0.5])) + vals = td.components.data.data_array.TimeDataArray([1, 2], coords={"t": [-1, -0.5]}) dataset = td.components.data.dataset.TimeDataset(values=vals) cst = td.CustomSourceTime(source_time_dataset=dataset, freq0=freq0, fwidth=0.1e12) source = td.PointDipole(center=(0, 0, 0), source_time=cst, polarization="Ex") @@ -386,7 +450,7 @@ def test_custom_source_time(): # test single value validation error with pytest.raises(pydantic.ValidationError): - vals = td.components.data.data_array.TimeDataArray([1], coords=dict(t=[0])) + vals = td.components.data.data_array.TimeDataArray([1], coords={"t": [0]}) dataset = td.components.data.dataset.TimeDataset(values=vals) cst = td.CustomSourceTime(source_time_dataset=dataset, freq0=freq0, fwidth=0.1e12) assert np.allclose(cst.amp_time([0]), [1], rtol=0, atol=ATOL) @@ -399,7 +463,7 @@ def test_custom_field_source(): Z = [0] freqs = [2e14] n_data = np.ones((Nx, Ny, Nz, Nf)) - n_dataset = td.ScalarFieldDataArray(n_data, coords=dict(x=X, y=Y, z=Z, f=freqs)) + n_dataset = td.ScalarFieldDataArray(n_data, coords={"x": X, "y": Y, "z": Z, "f": freqs}) def make_custom_field_source(field_ds): custom_source = td.CustomFieldSource( @@ -413,9 +477,9 @@ def make_custom_field_source(field_ds): with pytest.raises(pydantic.ValidationError): # repeat some entries so data cannot be interpolated - X2 = [X[0]] + list(X) + X2 = [X[0], *list(X)] n_data2 = np.vstack((n_data[0, :, :, :].reshape(1, Ny, Nz, Nf), n_data)) - n_dataset2 = td.ScalarFieldDataArray(n_data2, coords=dict(x=X2, y=Y, z=Z, f=freqs)) + n_dataset2 = td.ScalarFieldDataArray(n_data2, coords={"x": X2, "y": Y, "z": Z, "f": freqs}) field_dataset = td.FieldDataset(Ex=n_dataset, Hy=n_dataset2) make_custom_field_source(field_dataset) @@ -456,3 +520,80 @@ def test_fixed_angle_source(): ) assert not plane_wave._is_fixed_angle + + +def test_broadband_angled_gaussian_warning(): + g = td.GaussianPulse(freq0=1e14, fwidth=0.8e14) + # Case 1: num_freqs = 3, angle_theta = np.pi / 3, should warn + with AssertLogLevel("WARNING", contains_str="number of frequencies"): + s = td.GaussianBeam( + size=(0, 1, 1), + source_time=g, + pol_angle=np.pi / 2, + direction="+", + angle_theta=np.pi / 3, + num_freqs=3, + ) + _ = td.Simulation( + size=(2, 2, 2), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.1), + sources=[s], + normalize_index=None, + ) + + # Case 2: Increasing to num_freqs = 10 should NOT warn + with AssertLogLevel(None): + s = td.GaussianBeam( + size=(0, 1, 1), + source_time=g, + pol_angle=np.pi / 2, + direction="+", + angle_theta=np.pi / 3, + num_freqs=10, + ) + _ = td.Simulation( + size=(2, 2, 2), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.1), + sources=[s], + normalize_index=None, + ) + + # Case 3: Case 2 but changed to astigmatic gaussian beam with one larger waist size should warn + with AssertLogLevel("WARNING", contains_str="number of frequencies"): + s = td.AstigmaticGaussianBeam( + size=(0, 1, 1), + source_time=g, + pol_angle=np.pi / 2, + direction="+", + angle_theta=np.pi / 3, + num_freqs=10, + waist_sizes=(1, 5), + ) + _ = td.Simulation( + size=(2, 2, 2), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.1), + sources=[s], + normalize_index=None, + ) + + # Case 4: Case 3 but with num_freqs = 1 should NOT warn (broadband treatment is off) + with AssertLogLevel(None): + s = td.AstigmaticGaussianBeam( + size=(0, 1, 1), + source_time=g, + pol_angle=np.pi / 2, + direction="+", + angle_theta=np.pi / 3, + num_freqs=1, + waist_sizes=(1, 5), + ) + _ = td.Simulation( + size=(2, 2, 2), + run_time=1e-12, + grid_spec=td.GridSpec.uniform(dl=0.1), + sources=[s], + normalize_index=None, + ) diff --git a/tests/test_components/test_structure.py b/tests/test_components/test_structure.py index 5deea90b42..04553e69d8 100644 --- a/tests/test_components/test_structure.py +++ b/tests/test_components/test_structure.py @@ -1,9 +1,12 @@ +from __future__ import annotations + import autograd as ag import autograd.numpy as anp import gdstk import numpy as np import pydantic.v1 as pd import pytest + import tidy3d as td @@ -30,7 +33,7 @@ def test_custom_medium_to_gds(tmp_path): f = np.array([td.C_0]) mx, my, mz, _ = np.meshgrid(x, y, z, f, indexing="ij", sparse=True) data = 1 + 1 / (1 + (mx - 1) ** 2 + my**2 + mz**2) - eps_diagonal_data = td.ScalarFieldDataArray(data, coords=dict(x=x, y=y, z=z, f=f)) + eps_diagonal_data = td.ScalarFieldDataArray(data, coords={"x": x, "y": y, "z": z, "f": f}) eps_components = {f"eps_{d}{d}": eps_diagonal_data for d in "xyz"} eps_dataset = td.PermittivityDataset(**eps_components) medium = td.CustomMedium(eps_dataset=eps_dataset, name="my_medium") @@ -62,7 +65,7 @@ def test_lower_dimension_custom_medium_to_gds(tmp_path): f = np.array([td.C_0]) mx, my, mz, _ = np.meshgrid(x, y, z, f, indexing="ij", sparse=True) data = 1 + 1 / (1 + (mx - 1) ** 2 + mz**2) - eps_diagonal_data = td.ScalarFieldDataArray(data, coords=dict(x=x, y=y, z=z, f=f)) + eps_diagonal_data = td.ScalarFieldDataArray(data, coords={"x": x, "y": y, "z": z, "f": f}) eps_components = {f"eps_{d}{d}": eps_diagonal_data for d in "xyz"} eps_dataset = td.PermittivityDataset(**eps_components) medium = td.CustomMedium(eps_dataset=eps_dataset, name="my_medium") @@ -86,7 +89,7 @@ def test_non_symmetric_custom_medium_to_gds(tmp_path): data = 1 + mx + 0 * my + (mz - 2) ** 2 print(data.min(), data.max()) - eps_diagonal_data = td.ScalarFieldDataArray(data, coords=dict(x=x, y=y, z=z, f=f)) + eps_diagonal_data = td.ScalarFieldDataArray(data, coords={"x": x, "y": y, "z": z, "f": f}) eps_components = {f"eps_{d}{d}": eps_diagonal_data for d in "xyz"} eps_dataset = td.PermittivityDataset(**eps_components) medium = td.CustomMedium(eps_dataset=eps_dataset, name="my_medium") diff --git a/tests/test_components/test_time_modulation.py b/tests/test_components/test_time_modulation.py index 96b03a4d70..5d6b741f46 100644 --- a/tests/test_components/test_time_modulation.py +++ b/tests/test_components/test_time_modulation.py @@ -1,10 +1,13 @@ """Tests space time modulation.""" +from __future__ import annotations + from math import isclose import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from ..utils import cartesian_to_unstructured @@ -16,7 +19,7 @@ X = np.linspace(-1, 1, NX) Y = np.linspace(-1, 1, NY) Z = np.linspace(-1, 1, NZ) -COORDS = dict(x=X, y=Y, z=Z) +COORDS = {"x": X, "y": Y, "z": Z} ARRAY_CMP = td.SpatialDataArray(np.random.random((NX, NY, NZ)) + 0.1j, coords=COORDS) ARRAY = td.SpatialDataArray(np.random.random((NX, NY, NZ)), coords=COORDS) @@ -212,6 +215,10 @@ def test_unsupported_modulated_medium_types(): with pytest.raises(pydantic.ValidationError): td.PECMedium(modulation_spec=modulation_spec) + # PMC cannot be modulated + with pytest.raises(pydantic.ValidationError): + td.PMCMedium(modulation_spec=modulation_spec) + # For Anisotropic medium, one should modulate the components, not the whole medium with pytest.raises(pydantic.ValidationError): td.AnisotropicMedium( @@ -261,7 +268,7 @@ def test_supported_modulated_medium_types(unstructured, z): # custom permittivity = td.SpatialDataArray( - np.ones((2, 2, len(z))) * 2, coords=dict(x=[1, 2], y=[1, 3], z=z) + np.ones((2, 2, len(z))) * 2, coords={"x": [1, 2], "y": [1, 3], "z": z} ) if unstructured: permittivity = cartesian_to_unstructured(permittivity, seed=345) diff --git a/tests/test_components/test_types.py b/tests/test_components/test_types.py index f992bbec8d..dbf93c88f9 100644 --- a/tests/test_components/test_types.py +++ b/tests/test_components/test_types.py @@ -1,10 +1,13 @@ """Tests type definitions.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + from tidy3d.components.base import Tidy3dBaseModel -from tidy3d.components.types import ArrayLike, Complex, Tuple, constrained_array +from tidy3d.components.types import ArrayLike, Complex, constrained_array def _test_validate_array_like(): @@ -89,7 +92,7 @@ def test_hash(): class MyClass(Tidy3dBaseModel): a: ArrayLike b: constrained_array(ndim=1) - c: Tuple[ArrayLike, ...] + c: tuple[ArrayLike, ...] c = MyClass(a=[1.0], b=[2.0, 1.0], c=([2.0, 1.0])) hash(c.json()) diff --git a/tests/test_components/test_viz.py b/tests/test_components/test_viz.py index 0efbf130e4..4a93435b53 100644 --- a/tests/test_components/test_viz.py +++ b/tests/test_components/test_viz.py @@ -1,15 +1,20 @@ """Tests visualization operations.""" +from __future__ import annotations + import matplotlib as mpl import matplotlib.pyplot as plt import pydantic.v1 as pd import pytest + import tidy3d as td from tidy3d import Box, Medium, Simulation, Structure -from tidy3d.components.viz import Polygon, set_default_labels_and_title +from tidy3d.components.viz import Polygon, restore_matplotlib_rcparams, set_default_labels_and_title from tidy3d.constants import inf from tidy3d.exceptions import Tidy3dKeyError +from ..utils import AssertLogLevel + pytestmark = pytest.mark.usefixtures("mpl_config_noninteractive") @@ -190,18 +195,17 @@ def plot_with_multi_viz_spec(alphas, facecolors, edgecolors, rng, use_viz_spec=T td.VisualizationSpec( facecolor=facecolors[idx], edgecolor=edgecolors[idx], alpha=alphas[idx] ) - for idx in range(0, len(alphas)) + for idx in range(len(alphas)) ] - media = [td.Medium(permittivity=2.25) for idx in range(0, len(viz_specs))] + media = [td.Medium(permittivity=2.25) for idx in range(len(viz_specs))] if use_viz_spec: media = [ - td.Medium(permittivity=2.25, viz_spec=viz_specs[idx]) - for idx in range(0, len(viz_specs)) + td.Medium(permittivity=2.25, viz_spec=viz_specs[idx]) for idx in range(len(viz_specs)) ] structures = [] - for idx in range(0, len(viz_specs)): - center = tuple(list(rng.uniform(-3, 3, 2)) + [0]) + for idx in range(len(viz_specs)): + center = (*list(rng.uniform(-3, 3, 2)), 0) size = tuple(rng.uniform(1, 2, 3)) box = td.Box(center=center, size=size) @@ -218,6 +222,17 @@ def plot_with_multi_viz_spec(alphas, facecolors, edgecolors, rng, use_viz_spec=T plt.show() +def test_no_matlab_install(monkeypatch): + """Test that the `VisualizationSpec` only throws a warning on validation if matplotlib is not installed.""" + monkeypatch.setattr("tidy3d.components.viz.visualization_spec.MATPLOTLIB_IMPORTED", False) + + EXPECTED_WARNING_MSG_PIECE = ( + "matplotlib was not successfully imported, but is required to validate colors" + ) + with AssertLogLevel("WARNING", contains_str=EXPECTED_WARNING_MSG_PIECE): + viz_spec = td.VisualizationSpec(facecolor="green") + + @pytest.mark.skip(reason="Skipping test for CI, but useful for debugging locally with graphics.") def test_plot_from_structure_local(): """ @@ -317,3 +332,13 @@ def test_sim_plot_structures_fill(): for patch in structure_patches[:1]: assert patch.get_fill(), "Should be filled when True" assert patch.get_facecolor() != "none", "Face color should be set" + + +def test_tidy3d_matplotlib_style_application_on_import(): + """Test restore_matplotlib_rcparams() to reset the automatically applied matplotlib.rcParams""" + assert mpl.rcParams.get("axes.prop_cycle").by_key()["color"][0] == "#176737" + restore_matplotlib_rcparams() + assert ( + mpl.rcParams.get("axes.prop_cycle").by_key()["color"][0] + == mpl.rcParamsDefault.get("axes.prop_cycle").by_key()["color"][0] + ) diff --git a/tests/test_data/test_data_arrays.py b/tests/test_data/test_data_arrays.py index f61123fb0d..f38f42572e 100644 --- a/tests/test_data/test_data_arrays.py +++ b/tests/test_data/test_data_arrays.py @@ -1,11 +1,14 @@ """Tests tidy3d/components/data/data_array.py""" -from typing import List, Tuple +from __future__ import annotations + +from typing import Optional import numpy as np import pytest -import tidy3d as td import xarray.testing as xrt + +import tidy3d as td from tidy3d.exceptions import DataError np.random.seed(4) @@ -124,7 +127,7 @@ def get_xyz( monitor: td.components.monitor.MonitorType, grid_key: str, symmetry: bool -) -> Tuple[List[float], List[float], List[float]]: +) -> tuple[list[float], list[float], list[float]]: sim = SIM_SYM if symmetry else SIM grid = sim.discretize_monitor(monitor) if monitor.colocate: @@ -138,22 +141,24 @@ def get_xyz( return x, y, z -def make_scalar_field_data_array(grid_key: str, symmetry=True, colocate: bool = None): +def make_scalar_field_data_array(grid_key: str, symmetry=True, colocate: Optional[bool] = None): monitor = FIELD_MONITOR if colocate is not None: monitor = monitor.updated_copy(colocate=colocate) XS, YS, ZS = get_xyz(monitor, grid_key, symmetry) values = (1 + 1j) * np.random.random((len(XS), len(YS), len(ZS), len(FS))) - return td.ScalarFieldDataArray(values, coords=dict(x=XS, y=YS, z=ZS, f=FS)) + return td.ScalarFieldDataArray(values, coords={"x": XS, "y": YS, "z": ZS, "f": FS}) def make_scalar_field_time_data_array(grid_key: str, symmetry=True): XS, YS, ZS = get_xyz(FIELD_TIME_MONITOR, grid_key, symmetry) values = np.random.random((len(XS), len(YS), len(ZS), len(TS))) - return td.ScalarFieldTimeDataArray(values, coords=dict(x=XS, y=YS, z=ZS, t=TS)) + return td.ScalarFieldTimeDataArray(values, coords={"x": XS, "y": YS, "z": ZS, "t": TS}) -def make_scalar_mode_field_data_array(grid_key: str, symmetry=True, colocate: bool = None): +def make_scalar_mode_field_data_array( + grid_key: str, symmetry=True, colocate: Optional[bool] = None +): monitor = MODE_MONITOR_WITH_FIELDS if colocate is not None: monitor = monitor.updated_copy(colocate=colocate) @@ -161,7 +166,7 @@ def make_scalar_mode_field_data_array(grid_key: str, symmetry=True, colocate: bo values = (1 + 0.1j) * np.random.random((len(XS), 1, len(ZS), len(FS), len(MODE_INDICES))) return td.ScalarModeFieldDataArray( - values, coords=dict(x=XS, y=[0.0], z=ZS, f=FS, mode_index=MODE_INDICES) + values, coords={"x": XS, "y": [0.0], "z": ZS, "f": FS, "mode_index": MODE_INDICES} ) @@ -180,35 +185,37 @@ def make_scalar_mode_field_data_array_smooth(grid_key: str, symmetry=True, rot: ) return td.ScalarModeFieldDataArray( - values, coords=dict(x=XS, y=[0.0], z=ZS, f=FS, mode_index=MODE_INDICES) + values, coords={"x": XS, "y": [0.0], "z": ZS, "f": FS, "mode_index": MODE_INDICES} ) def make_mode_amps_data_array(): values = (1 + 1j) * np.random.random((len(DIRECTIONS), len(MODE_INDICES), len(FS))) return td.ModeAmpsDataArray( - values, coords=dict(direction=DIRECTIONS, mode_index=MODE_INDICES, f=FS) + values, coords={"direction": DIRECTIONS, "mode_index": MODE_INDICES, "f": FS} ) def make_mode_index_data_array(): values = (1 + 0.1j) * np.random.random((len(FS), len(MODE_INDICES))) - return td.ModeIndexDataArray(values, coords=dict(f=FS, mode_index=MODE_INDICES)) + return td.ModeIndexDataArray(values, coords={"f": FS, "mode_index": MODE_INDICES}) def make_far_field_data_array(): values = (1 + 1j) * np.random.random((len(PD), len(THETAS), len(PHIS), len(FS))) - return td.FieldProjectionAngleDataArray(values, coords=dict(r=PD, theta=THETAS, phi=PHIS, f=FS)) + return td.FieldProjectionAngleDataArray( + values, coords={"r": PD, "theta": THETAS, "phi": PHIS, "f": FS} + ) def make_flux_data_array(): values = np.random.random(len(FS)) - return td.FluxDataArray(values, coords=dict(f=FS)) + return td.FluxDataArray(values, coords={"f": FS}) def make_flux_time_data_array(): values = np.random.random(len(TS)) - return td.FluxTimeDataArray(values, coords=dict(t=TS)) + return td.FluxTimeDataArray(values, coords={"t": TS}) def make_diffraction_data_array(): @@ -216,7 +223,9 @@ def make_diffraction_data_array(): return ( [SIZE_2D[0], SIZE_2D[2]], [1.0, 2.0], - td.DiffractionDataArray(values, coords=dict(orders_x=ORDERS_X, orders_y=ORDERS_Y, f=FS)), + td.DiffractionDataArray( + values, coords={"orders_x": ORDERS_X, "orders_y": ORDERS_Y, "f": FS} + ), ) @@ -293,11 +302,11 @@ def test_ops(): def test_empty_field_time(): _ = td.ScalarFieldTimeDataArray( np.random.rand(5, 5, 5, 0), - coords=dict(x=np.arange(5), y=np.arange(5), z=np.arange(5), t=[]), + coords={"x": np.arange(5), "y": np.arange(5), "z": np.arange(5), "t": []}, ) _ = td.ScalarFieldTimeDataArray( np.random.rand(5, 5, 5, 0), - coords=dict(x=np.arange(5), y=np.arange(5), z=np.arange(5), t=[]), + coords={"x": np.arange(5), "y": np.arange(5), "z": np.arange(5), "t": []}, ) @@ -308,7 +317,7 @@ def test_abs(): def test_heat_data_array(): T = [0, 1e-12, 2e-12] - _ = td.HeatDataArray((1 + 1j) * np.random.random((3,)), coords=dict(T=T)) + _ = td.HeatDataArray((1 + 1j) * np.random.random((3,)), coords={"T": T}) def test_steady_voltage_data_array(): @@ -320,34 +329,34 @@ def test_steady_voltage_data_array(): def test_charge_data_array(): n = [0, 1e-12, 2e-12] p = [0, 3e-12, 4e-12] - _ = td.ChargeDataArray((1 + 1j) * np.random.random((3, 3)), coords=dict(n=n, p=p)) + _ = td.ChargeDataArray((1 + 1j) * np.random.random((3, 3)), coords={"n": n, "p": p}) def test_point_data_array(): _ = td.PointDataArray( np.random.rand(2, 3), - coords=dict(index=np.arange(2), axis=np.arange(3)), + coords={"index": np.arange(2), "axis": np.arange(3)}, ) def test_cell_data_array(): _ = td.CellDataArray( [[0, 1, 2], [1, 2, 3]], - coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)), + coords={"cell_index": np.arange(2), "vertex_index": np.arange(3)}, ) def test_indexed_data_array(): _ = td.IndexedDataArray( np.random.rand(10), - coords=dict(index=np.arange(10)), + coords={"index": np.arange(10)}, ) def test_spatial_data_array(): arr = td.SpatialDataArray( [[[0, 1], [2, 3]], [[4, 5], [6, 7]]], - coords=dict(x=[0, 1], y=[1, 2], z=[2, 3]), + coords={"x": [0, 1], "y": [1, 2], "z": [2, 3]}, ) # make it non sorted @@ -358,7 +367,7 @@ def test_spatial_data_array(): reflected_expected = td.SpatialDataArray( [[[4, 5], [6, 7]], [[0, 1], [2, 3]], [[0, 1], [2, 3]], [[4, 5], [6, 7]]], - coords=dict(x=[-2, -1, 0, 1], y=[1, 2], z=[2, 3]), + coords={"x": [-2, -1, 0, 1], "y": [1, 2], "z": [2, 3]}, ) assert reflected == reflected_expected @@ -368,7 +377,7 @@ def test_spatial_data_array(): reflected_expected = td.SpatialDataArray( [[[4, 5], [6, 7]], [[0, 1], [2, 3]]], - coords=dict(x=[-2, -1], y=[1, 2], z=[2, 3]), + coords={"x": [-2, -1], "y": [1, 2], "z": [2, 3]}, ) assert reflected == reflected_expected @@ -378,7 +387,7 @@ def test_spatial_data_array(): reflected_expected = td.SpatialDataArray( [[[2, 3], [0, 1], [2, 3]], [[6, 7], [4, 5], [6, 7]]], - coords=dict(x=[0, 1], y=[0, 1, 2], z=[2, 3]), + coords={"x": [0, 1], "y": [0, 1, 2], "z": [2, 3]}, ) assert reflected == reflected_expected @@ -388,7 +397,7 @@ def test_spatial_data_array(): reflected_expected = td.SpatialDataArray( [[[2, 3], [0, 1]], [[6, 7], [4, 5]]], - coords=dict(x=[0, 1], y=[0, 1], z=[2, 3]), + coords={"x": [0, 1], "y": [0, 1], "z": [2, 3]}, ) assert reflected == reflected_expected @@ -403,11 +412,11 @@ def test_sel_inside(nx): nz = 12 arr = td.SpatialDataArray( np.random.random((nx, ny, nz)), - coords=dict( - x=np.linspace(0, 1, nx), - y=np.linspace(2, 3, ny), - z=np.linspace(0, 2, nz), - ), + coords={ + "x": np.linspace(0, 1, nx), + "y": np.linspace(2, 3, ny), + "z": np.linspace(0, 2, nz), + }, ) bounds_small = [[0.1, 2, 2], [1, 2.5, 2]] @@ -429,20 +438,20 @@ def test_uniform_check(): """check if each element in the array is of equal value.""" arr = td.SpatialDataArray( np.ones((2, 2, 2), dtype=np.complex128), - coords=dict(x=[0, 1], y=[1, 2], z=[2, 3]), + coords={"x": [0, 1], "y": [1, 2], "z": [2, 3]}, ) assert arr.is_uniform # small variation is still considered as uniform arr = td.SpatialDataArray( np.ones((2, 2, 2)) + np.random.random((2, 2, 2)) * 1e-6, - coords=dict(x=[0, 1], y=[1, 2], z=[2, 3]), + coords={"x": [0, 1], "y": [1, 2], "z": [2, 3]}, ) assert arr.is_uniform arr = td.SpatialDataArray( np.ones((2, 2, 2)) + np.random.random((2, 2, 2)) * 1e-4, - coords=dict(x=[0, 1], y=[1, 2], z=[2, 3]), + coords={"x": [0, 1], "y": [1, 2], "z": [2, 3]}, ) assert not arr.is_uniform diff --git a/tests/test_data/test_datasets.py b/tests/test_data/test_datasets.py index e6797ac9b7..b3602ff507 100644 --- a/tests/test_data/test_datasets.py +++ b/tests/test_data/test_datasets.py @@ -1,4 +1,6 @@ -"""Tests tidy3d/components/data/dataset.py""" +"""Tests tidy3d/components/tests//dataset.py""" + +from __future__ import annotations import numpy as np import pydantic.v1 as pd @@ -10,7 +12,7 @@ np.random.seed(4) -@pytest.mark.parametrize("dataset_type_ind", [0, 1]) +@pytest.mark.parametrize("dataset_type_ind", [0, 1, 2]) @pytest.mark.parametrize("ds_name", ["test123", None]) def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): import tidy3d as td @@ -26,6 +28,11 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): values_type = td.IndexedVoltageDataArray extra_dims = {"voltage": [0, 1, 2]} + if dataset_type_ind == 2: + dataset_type = td.TriangularGridDataset + values_type = td.IndexedTimeDataArray + extra_dims = {"t": [0, 1, 2]} + # basic create tri_grid_points = td.PointDataArray( [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], @@ -58,7 +65,7 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): with pytest.raises(pd.ValidationError): tri_grid_points_bad = td.PointDataArray( np.random.random((4, 3)), - coords=dict(index=np.arange(4), axis=np.arange(3)), + coords={"index": np.arange(4), "axis": np.arange(3)}, ) _ = dataset_type( @@ -72,7 +79,7 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): # grid with degenerate cells tri_grid_cells_bad = td.CellDataArray( [[0, 1, 1], [1, 2, 3]], - coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)), + coords={"cell_index": np.arange(2), "vertex_index": np.arange(3)}, ) with AssertLogLevel("WARNING"): @@ -108,7 +115,7 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): # invalid cell connections tri_grid_cells_bad = td.CellDataArray( [[0, 1, 2, 3]], - coords=dict(cell_index=np.arange(1), vertex_index=np.arange(4)), + coords={"cell_index": np.arange(1), "vertex_index": np.arange(4)}, ) with pytest.raises(pd.ValidationError): _ = dataset_type( @@ -121,7 +128,7 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): tri_grid_cells_bad = td.CellDataArray( [[0, 1, 5], [1, 2, 3]], - coords=dict(cell_index=np.arange(2), vertex_index=np.arange(3)), + coords={"cell_index": np.arange(2), "vertex_index": np.arange(3)}, ) with pytest.raises(pd.ValidationError): _ = dataset_type( @@ -254,7 +261,7 @@ def test_triangular_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): _ = tri_grid_one_field.plot(vmin=-20, vmax=100) plt.close() - _ = tri_grid_one_field.plot(cbar_kwargs=dict(label="test")) + _ = tri_grid_one_field.plot(cbar_kwargs={"label": "test"}) plt.close() _ = tri_grid_one_field.plot(cmap="RdBu") @@ -322,7 +329,7 @@ def operation(arr): assert result.name == ds_name -@pytest.mark.parametrize("dataset_type_ind", [0, 1]) +@pytest.mark.parametrize("dataset_type_ind", [0, 1, 2]) @pytest.mark.parametrize("ds_name", ["test123", None]) def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): import tidy3d as td @@ -338,6 +345,11 @@ def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): values_type = td.IndexedVoltageDataArray extra_dims = {"voltage": [0, 1, 2]} + if dataset_type_ind == 2: + dataset_type = td.TetrahedralGridDataset + values_type = td.IndexedTimeDataArray + extra_dims = {"t": [0, 1, 2]} + # basic create tet_grid_points = td.PointDataArray( [ @@ -373,7 +385,7 @@ def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): # wrong points dimensionality tet_grid_points_bad = td.PointDataArray( np.random.random((8, 2)), - coords=dict(index=np.arange(8), axis=np.arange(2)), + coords={"index": np.arange(8), "axis": np.arange(2)}, ) with pytest.raises(pd.ValidationError): _ = dataset_type( @@ -385,7 +397,7 @@ def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): # grid with degenerate cells tet_grid_cells_bad = td.CellDataArray( [[0, 1, 1, 7], [0, 2, 3, 7], [0, 2, 2, 7], [0, 4, 6, 7], [0, 4, 5, 7], [0, 5, 5, 7]], - coords=dict(cell_index=np.arange(6), vertex_index=np.arange(4)), + coords={"cell_index": np.arange(6), "vertex_index": np.arange(4)}, ) with AssertLogLevel("WARNING"): @@ -419,7 +431,7 @@ def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): # invalid cell connections tet_grid_cells_bad = td.CellDataArray( [[0, 1, 3], [0, 2, 3], [0, 2, 6], [0, 4, 6], [0, 4, 5], [0, 1, 5]], - coords=dict(cell_index=np.arange(6), vertex_index=np.arange(3)), + coords={"cell_index": np.arange(6), "vertex_index": np.arange(3)}, ) with pytest.raises(pd.ValidationError): _ = dataset_type( @@ -430,7 +442,7 @@ def test_tetrahedral_dataset(tmp_path, ds_name, dataset_type_ind, no_vtk=False): tet_grid_cells_bad = td.CellDataArray( [[0, 1, 3, 17], [0, 2, 3, 7], [0, 2, 6, 7], [0, 4, 6, 7], [0, 4, 5, 7], [0, 1, 5, 7]], - coords=dict(cell_index=np.arange(6), vertex_index=np.arange(4)), + coords={"cell_index": np.arange(6), "vertex_index": np.arange(4)}, ) with pytest.raises(pd.ValidationError): _ = dataset_type( @@ -605,7 +617,7 @@ def test_cartesian_to_unstructured(nz, use_vtk, fill_value): z = np.linspace(-0.2, 0.15, nz) values = np.sin(x[:, None, None]) * np.cos(y[None, :, None]) * np.exp(z[None, None, :]) - arr_c = td.SpatialDataArray(values, coords=dict(x=x, y=y, z=z)) + arr_c = td.SpatialDataArray(values, coords={"x": x, "y": y, "z": z}) arr_u_linear = cartesian_to_unstructured(arr_c, pert=0.1, method="linear", seed=123) arr_c_linear = arr_u_linear.interp( @@ -686,7 +698,7 @@ def test_cell_values(): tri_grid_values = td.IndexedVoltageDataArray( [[0.0, 0.0], [0, 0], [3, -3], [3, -3]], - coords=dict(index=np.arange(4), voltage=[-1, 1]), + coords={"index": np.arange(4), "voltage": [-1, 1]}, name="test", ) @@ -723,7 +735,7 @@ def test_cell_values(): ) tet_grid_values = td.IndexedDataArray( - [0.0, 0.0, 0.0, 0.0, 3.0, 3.0, 3.0, 3.0], coords=dict(index=np.arange(8)), name="test_tet" + [0.0, 0.0, 0.0, 0.0, 3.0, 3.0, 3.0, 3.0], coords={"index": np.arange(8)}, name="test_tet" ) tet_grid = td.TetrahedralGridDataset( @@ -739,3 +751,19 @@ def test_cell_values(): cell_values = tet_grid.get_cell_values() cell_vols = tet_grid.get_cell_volumes() assert np.dot(cell_values, cell_vols) == 1.5 + + +def test_from_vtk(): + """Test that 2D and 3D vtk data can be loaded if `ignore_invalid_cells==True`.""" + import tidy3d as td + from tidy3d.exceptions import DataError + + _ = td.TetrahedralGridDataset.from_vtk("tests/data/gmsh.vtk", ignore_invalid_cells=True) + + with pytest.raises(DataError): + _ = td.TetrahedralGridDataset.from_vtk("tests/data/gmsh.vtk") + + _ = td.TriangularGridDataset.from_vtk("tests/data/gmsh_2d.vtk", ignore_invalid_cells=True) + + with pytest.raises(DataError): + _ = td.TriangularGridDataset.from_vtk("tests/data/gmsh_2d.vtk") diff --git a/tests/test_data/test_monitor_data.py b/tests/test_data/test_monitor_data.py index 5ea9d6a6cc..c0f70d6454 100644 --- a/tests/test_data/test_monitor_data.py +++ b/tests/test_data/test_monitor_data.py @@ -1,11 +1,14 @@ """Tests tidy3d/components/data/monitor_data.py""" +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td import xarray as xr + +import tidy3d as td from tidy3d.components.data.data_array import ( FreqDataArray, FreqModeDataArray, @@ -239,17 +242,17 @@ def make_field_dataset_using_power_density( phi=phi, ) - coords = dict(r=r_proj, theta=theta, phi=phi, f=freqs) + coords = {"r": r_proj, "theta": theta, "phi": phi, "f": freqs} field = td.FieldProjectionAngleDataArray(values, coords=coords) - field_components = dict( - Er=field, - Etheta=field, - Ephi=field, - Hr=field, - Htheta=-1.0 * field, - Hphi=field, - ) + field_components = { + "Er": field, + "Etheta": field, + "Ephi": field, + "Hr": field, + "Htheta": -1.0 * field, + "Hphi": field, + } field_dataset = xr.Dataset(field_components) return monitor, field_dataset @@ -398,7 +401,7 @@ def test_directivity_data(planar_monitor): _ = data.flux f = data.flux.f.values # make some dummy data to represent power supplied to antenna - power_in = FreqDataArray(np.abs(np.random.random(size=np.shape(f))), coords=dict(f=f)) + power_in = FreqDataArray(np.abs(np.random.random(size=np.shape(f))), coords={"f": f}) assert isinstance(data.partial_radiation_intensity(), xr.Dataset) assert isinstance(data.radiation_intensity, xr.DataArray) assert isinstance(data.partial_directivity(), xr.Dataset) @@ -661,7 +664,7 @@ def test_data_array_hdf5_no_warnings(tmp_path): def test_diffraction_data_use_medium(): data = make_diffraction_data() - data = data.copy(update=dict(medium=td.Medium(permittivity=4))) + data = data.copy(update={"medium": td.Medium(permittivity=4)}) assert np.allclose(data.eta, np.real(td.ETA_0 / 2.0)) @@ -863,7 +866,7 @@ def test_no_nans(): eps_nan = eps_data.eps_xx.isel(f=[0]) eps_nan[:] = np.nan eps_dataset_nan = td.PermittivityDataset( - **{key: eps_nan for key in ["eps_xx", "eps_yy", "eps_zz"]} + **dict.fromkeys(["eps_xx", "eps_yy", "eps_zz"], eps_nan) ) with pytest.raises(pydantic.ValidationError): td.CustomMedium(eps_dataset=eps_dataset_nan) @@ -917,7 +920,7 @@ def mode_data(self) -> td.ModeData: return self.simdata(monitor)["modes"] @pytest.mark.parametrize("background_index", [1, 2, 3]) - @pytest.mark.parametrize("freq", list(freqs) + [None]) + @pytest.mark.parametrize("freq", [*list(freqs), None]) @pytest.mark.parametrize("n_x", [2**5, 2**6]) @pytest.mark.parametrize("n_y", [2**5, 2**6]) @pytest.mark.parametrize("units", ["mm", "cm", "in", "m"]) diff --git a/tests/test_data/test_sim_data.py b/tests/test_data/test_sim_data.py index d2569fb20a..2ea3da663d 100644 --- a/tests/test_data/test_sim_data.py +++ b/tests/test_data/test_sim_data.py @@ -1,9 +1,12 @@ """Tests SimulationData""" +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.data.data_array import ScalarFieldTimeDataArray from tidy3d.components.data.monitor_data import FieldTimeData @@ -388,12 +391,12 @@ def test_run_time_lt_start(tmp_path): normalize_index=None, ) - coords = dict( - x=np.linspace(-0.6, 0.6, 10), - y=np.linspace(-0.6, 0.6, 10), - z=[0.1], - t=[], - ) + coords = { + "x": np.linspace(-0.6, 0.6, 10), + "y": np.linspace(-0.6, 0.6, 10), + "z": [0.1], + "t": [], + } field_components = { field_name: ScalarFieldTimeDataArray(np.zeros((10, 10, 1, 0)), coords=coords) @@ -429,9 +432,9 @@ def test_plot_field_title(): def test_missing_monitor(): sim_data = make_sim_data() new_monitors = list(sim_data.simulation.monitors)[:-1] - new_sim = sim_data.simulation.copy(update=dict(monitors=new_monitors)) + new_sim = sim_data.simulation.copy(update={"monitors": new_monitors}) with pytest.raises(pydantic.ValidationError): - _ = sim_data.copy(update=dict(simulation=new_sim)) + _ = sim_data.copy(update={"simulation": new_sim}) def test_loading_non_field_data(): diff --git a/tests/test_material_library/test_material_library.py b/tests/test_material_library/test_material_library.py index 53a11dd94b..681bf86c29 100644 --- a/tests/test_material_library/test_material_library.py +++ b/tests/test_material_library/test_material_library.py @@ -1,5 +1,9 @@ """Tests material library functions and pretty printing""" +from __future__ import annotations + +from rich.console import Console + import tidy3d as td from tidy3d.material_library.material_library import MaterialItemUniaxial @@ -9,6 +13,12 @@ def test_material_library_summary(): print(td.material_library) +def test_material_library_rich_console(): + """Test the rich representation of the material library which validates its styles etc.""" + console = Console() + console.print(td.material_library) + + def test_material_summary(): """Test the string method for each material in the material library.""" @@ -61,20 +71,20 @@ def test_medium_repr(): repr_noname_medium = test_media[0].__repr__() str_noname_medium_dict = str(noname_medium_in_dict) - assert ( - "type='Medium' permittivity=2.25 conductivity=0.0" in str_noname_medium - ), "Expected medium information in string" - assert ( - "Medium(attrs={}, name=None, frequency_range=None" in repr_noname_medium - ), "Expcted medium information in repr" + assert "type='Medium' permittivity=2.25 conductivity=0.0" in str_noname_medium, ( + "Expected medium information in string" + ) + assert "Medium(attrs={}, name=None, frequency_range=None" in repr_noname_medium, ( + "Expcted medium information in repr" + ) assert repr_noname_medium in str_noname_medium_dict, "Expected repr in dictionary string" for medium in test_media: repr_str = medium.__repr__() - assert ( - test_media[1].__repr__() == material_name - ), "Expected repr to return just the material name." + assert test_media[1].__repr__() == material_name, ( + "Expected repr to return just the material name." + ) def test_variant_str(): @@ -87,16 +97,16 @@ def test_variant_str(): printed_SiO2_Palik_lossless = str(td.material_library["SiO2"].variants["Palik_Lossless"]) - assert ( - "eps_inf: 1.5385442336875639" in printed_SiO2_Palik_lossless - ), "Expected eps_inf in SiO2 printed string" + assert "eps_inf: 1.5385442336875639" in printed_SiO2_Palik_lossless, ( + "Expected eps_inf in SiO2 printed string" + ) assert "poles: 2" in printed_SiO2_Palik_lossless, "Expected 1 pole in SiO2 printed string" printed_SiO2_Palik_lossy = str(td.material_library["SiO2"].variants["Palik_Lossy"]) - assert ( - "eps_inf: 2.1560362571240765" in printed_SiO2_Palik_lossy - ), "Expected eps_inf in SiO2 printed string" + assert "eps_inf: 2.1560362571240765" in printed_SiO2_Palik_lossy, ( + "Expected eps_inf in SiO2 printed string" + ) assert "poles: 5" in printed_SiO2_Palik_lossy, "Expected 1 pole in SiO2 printed string" @@ -105,9 +115,9 @@ def test_material_str(): printed_Ag = str(td.material_library["Ag"]) - assert ( - "Default Variant: Rakic1998BB" in printed_Ag - ), "Expected default variant in printed string" + assert "Default Variant: Rakic1998BB" in printed_Ag, ( + "Expected default variant in printed string" + ) assert "RakicLorentzDrude1998" in printed_Ag, "Expected variant in printed string" printed_Au = str(td.material_library["Au"]) diff --git a/tests/test_package/test_compat.py b/tests/test_package/test_compat.py index 17005c9046..e079bbe509 100644 --- a/tests/test_package/test_compat.py +++ b/tests/test_package/test_compat.py @@ -1,4 +1,5 @@ # test_compat.py +from __future__ import annotations import importlib import sys diff --git a/tests/test_package/test_config.py b/tests/test_package/test_config.py index 63b31e86a7..f589494ac6 100644 --- a/tests/test_package/test_config.py +++ b/tests/test_package/test_config.py @@ -1,7 +1,10 @@ """test the grid operations""" +from __future__ import annotations + import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.log import DEFAULT_LEVEL, _level_value diff --git a/tests/test_package/test_convert.py b/tests/test_package/test_convert.py index fb7d5e741f..06e8e6bf1a 100644 --- a/tests/test_package/test_convert.py +++ b/tests/test_package/test_convert.py @@ -1,6 +1,9 @@ """Test converting .lsf files to Tidy3D python files.""" +from __future__ import annotations + import pytest + from tidy3d.web.cli.app import convert diff --git a/tests/test_package/test_log.py b/tests/test_package/test_log.py index bc72d5b316..b90414d3d6 100644 --- a/tests/test_package/test_log.py +++ b/tests/test_package/test_log.py @@ -1,10 +1,13 @@ """Test the logging.""" +from __future__ import annotations + import json import numpy as np import pydantic.v1 as pd import pytest + import tidy3d as td from tidy3d.exceptions import Tidy3dError from tidy3d.log import DEFAULT_LEVEL, _get_level_int, set_logging_level @@ -77,18 +80,18 @@ def test_logging_warning_capture(): center=(0, 0, 0), size=(domain_size, 0, domain_size), # additional frequency is outside the source range, but is inside the allowed validator range - freqs=list(freqs) + [0.1 * f0], + freqs=[*list(freqs), 0.1 * f0], mode_spec=td.ModeSpec(num_modes=3), name="mode", ) - # 2 warnings: too high num_freqs; too many points + # 1 warning: too many points mode_source = td.ModeSource( size=(domain_size, 0, domain_size), source_time=source_time, mode_spec=td.ModeSpec(num_modes=2, precision="single"), mode_index=1, - num_freqs=50, + num_freqs=10, direction="-", ) @@ -215,7 +218,7 @@ def test_logging_warning_capture(): sim.validate_pre_upload() warning_list = td.log.captured_warnings() print(json.dumps(warning_list, indent=4)) - assert len(warning_list) == 30 + assert len(warning_list) == 29 td.log.set_capture(False) # check that capture doesn't change validation errors diff --git a/tests/test_package/test_main.py b/tests/test_package/test_main.py index e55b39d622..120ae7fcb1 100644 --- a/tests/test_package/test_main.py +++ b/tests/test_package/test_main.py @@ -1,6 +1,9 @@ """Test running tidy3d as command line application.""" +from __future__ import annotations + import pytest + import tidy3d as td from tidy3d.__main__ import main diff --git a/tests/test_package/test_make_script.py b/tests/test_package/test_make_script.py index 235d75396f..39ce1686f4 100644 --- a/tests/test_package/test_make_script.py +++ b/tests/test_package/test_make_script.py @@ -1,5 +1,7 @@ """Tests generation of pythons script from simulation file.""" +from __future__ import annotations + import tidy3d as td from scripts.make_script import main @@ -29,4 +31,4 @@ def test_make_script(tmp_path): # make sure that file was created and is not empty assert out_path.is_file(), f"out file {out_path} wasn't created." - assert len(out_path.read_text()) > 0, f"out file {out_path} is empty." + assert len(out_path.read_text(encoding="utf-8")) > 0, f"out file {out_path} is empty." diff --git a/tests/test_package/test_material_library.py b/tests/test_package/test_material_library.py index 649182de87..1b988c43f4 100644 --- a/tests/test_package/test_material_library.py +++ b/tests/test_package/test_material_library.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.components.material.multi_physics import MultiPhysicsMedium from tidy3d.material_library.material_library import ( @@ -47,12 +50,14 @@ def test_MaterialItem(): medium=td.PoleResidue(), reference=[ReferenceData(doi="etc2.com", journal="paper2", url="www2")], ) - material = MaterialItem(name="material", variants=dict(v1=variant1, v2=variant2), default="v1") + material = MaterialItem( + name="material", variants={"v1": variant1, "v2": variant2}, default="v1" + ) assert material["v1"] == material.medium with pytest.raises(pydantic.ValidationError): material = MaterialItem( - name="material", variants=dict(v1=variant1, v2=variant2), default="v3" + name="material", variants={"v1": variant1, "v2": variant2}, default="v3" ) @@ -132,7 +137,7 @@ def test_uniaxial_material(): extraordinary=td.PoleResidue(eps_inf=6), ) material = MaterialItemUniaxial( - name="material", variants=dict(v1=variant1, v2=variant2), default="v1" + name="material", variants={"v1": variant1, "v2": variant2}, default="v1" ) for optical_axis in range(3): diff --git a/tests/test_package/test_parametric_variants.py b/tests/test_package/test_parametric_variants.py index 46aa58c6fc..ddd0d94bbc 100644 --- a/tests/test_package/test_parametric_variants.py +++ b/tests/test_package/test_parametric_variants.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import numpy as np import pytest from numpy.random import default_rng + from tidy3d.material_library.parametric_materials import ( GRAPHENE_FIT_ATOL, GRAPHENE_FIT_FREQ_MAX, diff --git a/tests/test_plugins/autograd/invdes/test_filters.py b/tests/test_plugins/autograd/invdes/test_filters.py index 2be94fedd7..ddab528e81 100644 --- a/tests/test_plugins/autograd/invdes/test_filters.py +++ b/tests/test_plugins/autograd/invdes/test_filters.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import pytest + from tidy3d.plugins.autograd.invdes.filters import ( _get_kernel_size, make_circular_filter, diff --git a/tests/test_plugins/autograd/invdes/test_parametrizations.py b/tests/test_plugins/autograd/invdes/test_parametrizations.py index aa31dec92d..31d8a8dc18 100644 --- a/tests/test_plugins/autograd/invdes/test_parametrizations.py +++ b/tests/test_plugins/autograd/invdes/test_parametrizations.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import autograd.numpy as np import pytest + from tidy3d.plugins.autograd.invdes.parametrizations import make_filter_and_project from tidy3d.plugins.autograd.types import PaddingType diff --git a/tests/test_plugins/autograd/invdes/test_penalties.py b/tests/test_plugins/autograd/invdes/test_penalties.py index 8ddad52675..7590c92c3c 100644 --- a/tests/test_plugins/autograd/invdes/test_penalties.py +++ b/tests/test_plugins/autograd/invdes/test_penalties.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import pytest + from tidy3d.plugins.autograd.invdes.penalties import make_erosion_dilation_penalty from tidy3d.plugins.autograd.types import PaddingType diff --git a/tests/test_plugins/autograd/primitives/test_interpolate.py b/tests/test_plugins/autograd/primitives/test_interpolate.py index a18d8e7ca3..e30b7a720d 100644 --- a/tests/test_plugins/autograd/primitives/test_interpolate.py +++ b/tests/test_plugins/autograd/primitives/test_interpolate.py @@ -1,7 +1,11 @@ +from __future__ import annotations + import autograd.numpy as np import numpy.testing as npt import pytest +from autograd import grad from autograd.test_util import check_grads + from tidy3d.plugins.autograd import interpolate_spline from ....utils import AssertLogLevel @@ -36,6 +40,22 @@ def test_interpolate_spline_grads(rng, order, num_points, endpoint_derivs, x_dis ) +def test_interpolate_spline_grads_kwargs(rng): + """Test interpolate_spline function can be called with kwargs.""" + x = np.linspace(0, 1, 10) + y = rng.random(x.size) + # this should not error + grad( + lambda y_: interpolate_spline( + x_points=x, + y_points=y_, + num_points=10, + order=3, + endpoint_derivatives=(None, None), + )[1][0] + )(y) + + @pytest.mark.parametrize("order", [1, 2, 3]) @pytest.mark.parametrize("x", [np.linspace(0, 1, 10), np.linspace(1, 0, 10)]) def test_interpolate_spline_vals(rng, order, x): diff --git a/tests/test_plugins/autograd/primitives/test_misc.py b/tests/test_plugins/autograd/primitives/test_misc.py index ce38b7a42d..6db99fd863 100644 --- a/tests/test_plugins/autograd/primitives/test_misc.py +++ b/tests/test_plugins/autograd/primitives/test_misc.py @@ -1,5 +1,9 @@ +from __future__ import annotations + +import autograd.numpy as np import pytest from autograd.test_util import check_grads + from tidy3d.plugins.autograd.primitives import gaussian_filter @@ -19,3 +23,19 @@ def test_gaussian_filter_grad(rng, size, ndim, sigma, mode): x = rng.random((size,) * ndim) check_grads(lambda x: gaussian_filter(x, sigma=sigma, mode=mode), modes=["rev"], order=2)(x) + + +@pytest.mark.parametrize("shape, axis", [((100,), -1), ((10, 12), 0), ((10, 12), 1)]) +@pytest.mark.parametrize("period", [np.pi, 2 * np.pi]) +@pytest.mark.parametrize("discont", [None, 0.6]) +def test_unwrap_grad(rng, shape, axis, period, discont): + """Test the gradient of the unwrap function with various arguments.""" + if discont is not None: + # discont must be > period / 2 to have an effect + discont = discont * period + + x = rng.uniform(-4 * period, 4 * period, shape) + + check_grads( + lambda x: np.unwrap(x, discont=discont, axis=axis, period=period), modes=["fwd", "rev"] + )(x) diff --git a/tests/test_plugins/autograd/test_differential_operators.py b/tests/test_plugins/autograd/test_differential_operators.py index 75879ea98c..296a218892 100644 --- a/tests/test_plugins/autograd/test_differential_operators.py +++ b/tests/test_plugins/autograd/test_differential_operators.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import autograd.numpy as np import pytest from autograd import grad as grad_ag from autograd import value_and_grad as value_and_grad_ag from numpy.testing import assert_allclose + from tidy3d.components.data.data_array import DataArray from tidy3d.plugins.autograd import grad, value_and_grad diff --git a/tests/test_plugins/autograd/test_functions.py b/tests/test_plugins/autograd/test_functions.py index 4c83a70f20..c08d648f63 100644 --- a/tests/test_plugins/autograd/test_functions.py +++ b/tests/test_plugins/autograd/test_functions.py @@ -1,10 +1,14 @@ +from __future__ import annotations + import numpy as np import numpy.testing as npt import pytest import scipy.interpolate import scipy.ndimage +from autograd import grad from autograd.test_util import check_grads from scipy.signal import convolve as convolve_sp + from tidy3d.plugins.autograd import ( add_at, convolve, @@ -197,7 +201,7 @@ def test_morphology_val_size(self, rng, op, sp_op, mode, ary_size, kernel_size): def test_morphology_val_grad(self, rng, op, sp_op, mode, ary_size, kernel_size): """Test gradients of morphological operations for various modes, array sizes, and kernel sizes.""" x = rng.random(ary_size) - check_grads(op, modes=["rev"], order=2)(x, size=kernel_size, mode=mode) + check_grads(op, modes=["rev"], order=1)(x, size=kernel_size, mode=mode) @pytest.mark.parametrize( "full", @@ -241,7 +245,71 @@ def test_morphology_val_structure_grad( ): """Test gradients of morphological operations for various kernel structures.""" x, k = self._ary_and_kernel(rng, ary_size, kernel_size, full, square, flat) - check_grads(op, modes=["rev"], order=2)(x, size=kernel_size, mode=mode) + check_grads(op, modes=["rev"], order=1)(x, structure=k, mode=mode) + + +class TestMorphology1D: + """Test morphological operations with 1D-like structuring elements.""" + + @pytest.mark.parametrize("h, w", [(1, 3), (3, 1), (1, 5), (5, 1)]) + def test_1d_structuring_elements(self, rng, h, w): + """Test grey dilation with 1D-like structuring elements on 2D arrays.""" + x = rng.random((8, 8)) + + # Test with size parameter + size_tuple = (h, w) + result_size = grey_dilation(x, size=size_tuple) + + # Verify output shape matches input + assert result_size.shape == x.shape + + # Verify that dilation actually increases values (or keeps them the same) + assert np.all(result_size >= x) + + # Test that we can also use structure parameter with 1D-like arrays + structure = np.ones((h, w)) + result_struct = grey_dilation(x, structure=structure) + assert result_struct.shape == x.shape + + def test_1d_gradient_flow(self, rng): + """Test gradient flow through 1D-like structuring elements.""" + x = rng.random((6, 6)) + + # Test horizontal 1D structure + check_grads(lambda x: grey_dilation(x, size=(1, 3)), modes=["rev"], order=1)(x) + + # Test vertical 1D structure + check_grads(lambda x: grey_dilation(x, size=(3, 1)), modes=["rev"], order=1)(x) + + # Test with structure parameter + struct_h = np.ones((1, 3)) + struct_v = np.ones((3, 1)) + check_grads(lambda x: grey_dilation(x, structure=struct_h), modes=["rev"], order=1)(x) + check_grads(lambda x: grey_dilation(x, structure=struct_v), modes=["rev"], order=1)(x) + + +class TestMorphologyExceptions: + """Test exceptions in morphological operations.""" + + def test_no_size_or_structure(self, rng): + """Test that an exception is raised when neither size nor structure is provided.""" + x = rng.random((5, 5)) + with pytest.raises(ValueError, match="Either size or structure must be provided"): + grey_dilation(x) + + def test_even_structure_dimensions(self, rng): + """Test that an exception is raised for even-dimensioned structuring elements.""" + x = rng.random((5, 5)) + k_even = np.ones((4, 4)) + with pytest.raises(ValueError, match="Structuring element dimensions must be odd"): + grey_dilation(x, structure=k_even) + + def test_both_size_and_structure(self, rng): + """Test that an exception is raised when both size and structure are provided.""" + x = rng.random((5, 5)) + k = np.ones((3, 3)) + with pytest.raises(ValueError, match="Cannot specify both size and structure"): + grey_dilation(x, size=3, structure=k) @pytest.mark.parametrize( @@ -387,6 +455,15 @@ def test_add_at_grad(self, rng, shape, indices): check_grads(lambda y: add_at(x, indices, y), modes=["fwd", "rev"], order=2)(y) +def test_add_at_grad_kwargs(rng): + """Test add_at function for different array dimensions and indices, with kwargs.""" + indices = (0,) + x = rng.uniform(-1, 1, (10,)) + y = rng.uniform(-1, 1, x[tuple(indices)].shape) + # this should not error + grad(lambda y_: add_at(x=x, y=y_, indices_x=indices)[0])(y) + + @pytest.mark.parametrize("shape", [(5,), (5, 5), (5, 5, 5)]) @pytest.mark.parametrize("tau", [1e-3, 1.0]) @pytest.mark.parametrize("axis", [None, 0, 1, -1]) diff --git a/tests/test_plugins/autograd/test_utilities.py b/tests/test_plugins/autograd/test_utilities.py index 68cf7a9706..c0aaecc4ee 100644 --- a/tests/test_plugins/autograd/test_utilities.py +++ b/tests/test_plugins/autograd/test_utilities.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import numpy as np import numpy.testing as npt import pytest import xarray as xr + from tidy3d.exceptions import Tidy3dError from tidy3d.plugins.autograd import ( chain, diff --git a/tests/test_plugins/expressions/test_functions.py b/tests/test_plugins/expressions/test_functions.py index d7942b545c..c4f039ca79 100644 --- a/tests/test_plugins/expressions/test_functions.py +++ b/tests/test_plugins/expressions/test_functions.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import numpy as np import pytest + from tidy3d.plugins.expressions.functions import Cos, Exp, Log, Log10, Sin, Sqrt, Tan from tidy3d.plugins.expressions.variables import Constant diff --git a/tests/test_plugins/expressions/test_operators.py b/tests/test_plugins/expressions/test_operators.py index d794a928fc..f9b80e25d3 100644 --- a/tests/test_plugins/expressions/test_operators.py +++ b/tests/test_plugins/expressions/test_operators.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import operator import numpy as np import pytest + from tidy3d.plugins.expressions.operators import ( Abs, Add, diff --git a/tests/test_plugins/expressions/test_variables.py b/tests/test_plugins/expressions/test_variables.py index 0d4818c9a8..da74b03dc0 100644 --- a/tests/test_plugins/expressions/test_variables.py +++ b/tests/test_plugins/expressions/test_variables.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import numpy as np import pytest + from tidy3d.plugins.expressions.variables import Constant, Variable diff --git a/tests/test_plugins/pytorch/test_wrapper.py b/tests/test_plugins/pytorch/test_wrapper.py index 2e80996c0c..441342af4c 100644 --- a/tests/test_plugins/pytorch/test_wrapper.py +++ b/tests/test_plugins/pytorch/test_wrapper.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import autograd.numpy as anp import torch from autograd import elementwise_grad from numpy.testing import assert_allclose + from tidy3d.plugins.pytorch.wrapper import to_torch @@ -41,3 +44,42 @@ def f_np(x, y): expected_grad = elementwise_grad(f_np, argnum=[0, 1])(x_np, y_np) assert_allclose(grad, expected_grad) + + +def test_to_torch_array_valued_function(rng): + """Test that gradients are computed correctly for functions returning arrays with different shapes than input.""" + x_np = rng.uniform(-1, 1, (2, 2)).astype("f4") + x_torch = torch.tensor(x_np, requires_grad=True) + + # define a function that returns a different shape than input + # this function maps (2,2) -> (2,3) + def f_np(x): + return anp.stack([x.sum(axis=1), x.mean(axis=1) * 2, x[:, 0] * x[:, 1]], axis=1) + + f_torch = to_torch(f_np) + + output = f_torch(x_torch) + assert output.shape == (2, 3) + + # create upstream gradient (simulating backprop from a loss) + grad_output = torch.ones_like(output) # shape (2, 3) + + output.backward(grad_output) + + h = 1e-5 + expected_grad = anp.zeros_like(x_np) + + for i in range(x_np.shape[0]): + for j in range(x_np.shape[1]): + x_plus = x_np.copy() + x_plus[i, j] += h + x_minus = x_np.copy() + x_minus[i, j] -= h + + f_plus = f_np(x_plus) + f_minus = f_np(x_minus) + + expected_grad[i, j] = anp.sum((f_plus - f_minus) / (2 * h)) + + computed_grad = x_torch.grad.numpy() + assert_allclose(computed_grad, expected_grad, rtol=1e-3, atol=1e-3) diff --git a/tests/test_plugins/smatrix/terminal_component_modeler_def.py b/tests/test_plugins/smatrix/terminal_component_modeler_def.py index e8b5eca779..f4b7e665d5 100644 --- a/tests/test_plugins/smatrix/terminal_component_modeler_def.py +++ b/tests/test_plugins/smatrix/terminal_component_modeler_def.py @@ -1,6 +1,9 @@ -from typing import Union +from __future__ import annotations + +from typing import Optional, Union import numpy as np + import tidy3d as td import tidy3d.plugins.microwave as microwave from tidy3d.plugins.smatrix import ( @@ -33,7 +36,9 @@ Router = 1.0 * mm -def make_simulation(planar_pec: bool, length: float = None, grid_spec: td.GridSpec = None): +def make_simulation( + planar_pec: bool, length: Optional[float] = None, grid_spec: td.GridSpec = None +): if length: strip_length = length else: @@ -109,7 +114,7 @@ def make_simulation(planar_pec: bool, length: float = None, grid_spec: td.GridSp def make_component_modeler( planar_pec: bool, reference_impedance: complex = 50, - length: float = None, + length: Optional[float] = None, port_refinement: bool = True, port_snapping: bool = True, grid_spec: td.GridSpec = None, @@ -167,7 +172,7 @@ def make_component_modeler( return modeler -def make_coaxial_simulation(length: float = None, grid_spec: td.GridSpec = None): +def make_coaxial_simulation(length: Optional[float] = None, grid_spec: td.GridSpec = None): if not length: length = default_strip_length @@ -244,7 +249,7 @@ def make_coaxial_simulation(length: float = None, grid_spec: td.GridSpec = None) def make_coaxial_component_modeler( reference_impedance: complex = 50, - length: float = None, + length: Optional[float] = None, port_refinement: bool = True, grid_spec: td.GridSpec = None, port_types: tuple[Union[CoaxialLumpedPort, WavePort], Union[CoaxialLumpedPort, WavePort]] = ( @@ -299,7 +304,9 @@ def make_port(center, direction, type, name) -> Union[CoaxialLumpedPort, WavePor normal_axis=2, clockwise=direction != "+", ) - + port_cells = None + if port_refinement: + port_cells = 5 port = WavePort( center=center, size=[2 * Router, 2 * Router, 0], @@ -309,6 +316,7 @@ def make_port(center, direction, type, name) -> Union[CoaxialLumpedPort, WavePor mode_index=0, voltage_integral=voltage_integral, current_integral=current_integral, + num_grid_cells=port_cells, ) return port diff --git a/tests/test_plugins/smatrix/test_component_modeler.py b/tests/test_plugins/smatrix/test_component_modeler.py index 9fa2477a3b..74064826d9 100644 --- a/tests/test_plugins/smatrix/test_component_modeler.py +++ b/tests/test_plugins/smatrix/test_component_modeler.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import gdstk import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td from tidy3d.exceptions import SetupError, Tidy3dKeyError from tidy3d.plugins.smatrix import ( @@ -203,9 +206,9 @@ def test_validate_no_sources(): source = td.PointDipole( source_time=td.GaussianPulse(freq0=2e14, fwidth=1e14), polarization="Ex" ) - sim_w_source = modeler.simulation.copy(update=dict(sources=(source,))) + sim_w_source = modeler.simulation.copy(update={"sources": (source,)}) with pytest.raises(pydantic.ValidationError): - _ = modeler.copy(update=dict(simulation=sim_w_source)) + _ = modeler.copy(update={"simulation": sim_w_source}) def test_element_mappings_none(): @@ -232,7 +235,7 @@ def test_ports_too_close_boundary(): port_center_at_edge = list(port_at_edge.center) port_center_at_edge[0] = edge_val port_at_edge = port_at_edge.copy( - update=dict(center=port_center_at_edge, direction=port_dir) + update={"center": port_center_at_edge, "direction": port_dir} ) with pytest.raises(SetupError): modeler._shift_value_signed(port=port_at_edge) @@ -275,15 +278,15 @@ def test_run_component_modeler(monkeypatch): for mode_index_in in range(port_in.mode_spec.num_modes): for port_out in modeler.ports: for mode_index_out in range(port_out.mode_spec.num_modes): - coords_in = dict(port_in=port_in.name, mode_index_in=mode_index_in) - coords_out = dict(port_out=port_out.name, mode_index_out=mode_index_out) + coords_in = {"port_in": port_in.name, "mode_index_in": mode_index_in} + coords_out = {"port_out": port_out.name, "mode_index_out": mode_index_out} - assert np.all( - s_matrix.sel(**coords_in) != 0 - ), "source index not present in S matrix" - assert np.all( - s_matrix.sel(**coords_in).sel(**coords_out) != 0 - ), "monitor index not present in S matrix" + assert np.all(s_matrix.sel(**coords_in) != 0), ( + "source index not present in S matrix" + ) + assert np.all(s_matrix.sel(**coords_in).sel(**coords_out) != 0), ( + "monitor index not present in S matrix" + ) def test_component_modeler_run_only(monkeypatch): @@ -294,7 +297,7 @@ def test_component_modeler_run_only(monkeypatch): modeler = make_component_modeler(run_only=run_only) s_matrix = run_component_modeler(monkeypatch, modeler) - coords_in_run_only = dict(port_in=port_run_only, mode_index_in=mode_index_run_only) + coords_in_run_only = {"port_in": port_run_only, "mode_index_in": mode_index_run_only} # make sure the run only mappings are non-zero assert np.all(s_matrix.sel(**coords_in_run_only) != 0) @@ -312,19 +315,19 @@ def _test_mappings(element_mappings, s_matrix): (port_out_to, mode_index_out_to) = k (port_in_to, mode_index_in_to) = L - coords_from = dict( - port_in=port_in_from, - port_out=port_out_from, - mode_index_in=mode_index_in_from, - mode_index_out=mode_index_out_from, - ) + coords_from = { + "port_in": port_in_from, + "port_out": port_out_from, + "mode_index_in": mode_index_in_from, + "mode_index_out": mode_index_out_from, + } - coords_to = dict( - port_in=port_in_to, - port_out=port_out_to, - mode_index_in=mode_index_in_to, - mode_index_out=mode_index_out_to, - ) + coords_to = { + "port_in": port_in_to, + "port_out": port_out_to, + "mode_index_in": mode_index_in_to, + "mode_index_out": mode_index_out_to, + } assert np.all( s_matrix.sel(**coords_to).values == mult_by * s_matrix.sel(**coords_from).values @@ -396,7 +399,7 @@ def test_to_from_file_batch(tmp_path, monkeypatch): modeler = make_component_modeler() _ = run_component_modeler(monkeypatch, modeler) - batch = td.web.Batch(simulations=dict()) + batch = td.web.Batch(simulations={}) modeler._cached_properties["batch"] = batch diff --git a/tests/test_plugins/smatrix/test_terminal_component_modeler.py b/tests/test_plugins/smatrix/test_terminal_component_modeler.py index 0c7b79a23c..c601d34e76 100644 --- a/tests/test_plugins/smatrix/test_terminal_component_modeler.py +++ b/tests/test_plugins/smatrix/test_terminal_component_modeler.py @@ -1,12 +1,19 @@ +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pd import pytest -import tidy3d as td import xarray as xr + +import tidy3d as td from tidy3d.components.data.data_array import FreqDataArray from tidy3d.exceptions import SetupError, Tidy3dError, Tidy3dKeyError -from tidy3d.plugins.microwave import CustomCurrentIntegral2D, VoltageIntegralAxisAligned +from tidy3d.plugins.microwave import ( + CurrentIntegralAxisAligned, + CustomCurrentIntegral2D, + VoltageIntegralAxisAligned, +) from tidy3d.plugins.smatrix import ( AbstractComponentModeler, CoaxialLumpedPort, @@ -21,6 +28,8 @@ from ...utils import run_emulated from .terminal_component_modeler_def import make_coaxial_component_modeler, make_component_modeler +mm = 1e3 + def run_component_modeler(monkeypatch, modeler: TerminalComponentModeler): sim_dict = modeler.sim_dict @@ -73,9 +82,9 @@ def test_validate_no_sources(tmp_path): source = td.PointDipole( source_time=td.GaussianPulse(freq0=2e14, fwidth=1e14), polarization="Ex" ) - sim_w_source = modeler.simulation.copy(update=dict(sources=(source,))) + sim_w_source = modeler.simulation.copy(update={"sources": (source,)}) with pytest.raises(pd.ValidationError): - _ = modeler.copy(update=dict(simulation=sim_w_source)) + _ = modeler.copy(update={"simulation": sim_w_source}) def test_validate_3D_sim(tmp_path): @@ -137,13 +146,13 @@ def test_run_component_modeler(monkeypatch, tmp_path): for port_in in modeler.ports: for port_out in modeler.ports: - coords_in = dict(port_in=port_in.name) - coords_out = dict(port_out=port_out.name) + coords_in = {"port_in": port_in.name} + coords_out = {"port_out": port_out.name} assert np.all(s_matrix.sel(**coords_in) != 0), "source index not present in S matrix" - assert np.all( - s_matrix.sel(**coords_in).sel(**coords_out) != 0 - ), "monitor index not present in S matrix" + assert np.all(s_matrix.sel(**coords_in).sel(**coords_out) != 0), ( + "monitor index not present in S matrix" + ) def test_s_to_z_component_modeler(): @@ -173,11 +182,11 @@ def test_s_to_z_component_modeler(): dtype=complex, ) # Put coords in opposite order to check reordering - coords = dict( - f=np.array(freqs), - port_out=port_names, - port_in=port_names, - ) + coords = { + "f": np.array(freqs), + "port_out": port_names, + "port_in": port_names, + } s_matrix = TerminalPortDataArray(data=values, coords=coords) z_matrix = TerminalComponentModeler.s_to_z(s_matrix, reference=Z0) @@ -189,10 +198,10 @@ def test_s_to_z_component_modeler(): # test version with different port reference impedances values = np.full((len(freqs), len(port_names)), Z0) - coords = dict( - f=np.array(freqs), - port=port_names, - ) + coords = { + "f": np.array(freqs), + "port": port_names, + } z_port_matrix = PortDataArray(data=values, coords=coords) z_matrix = TerminalComponentModeler.s_to_z(s_matrix, reference=z_port_matrix) z_matrix_at_f = z_matrix.sel(f=1e8) @@ -203,11 +212,11 @@ def test_s_to_z_component_modeler(): def test_ab_to_s_component_modeler(): - coords = dict( - f=np.array([1e8]), - port_out=["lumped_port_1", "lumped_port_2"], - port_in=["lumped_port_1", "lumped_port_2"], - ) + coords = { + "f": np.array([1e8]), + "port_out": ["lumped_port_1", "lumped_port_2"], + "port_in": ["lumped_port_1", "lumped_port_2"], + } # Common case is reference impedance matched to loads, which means ideally # the a matrix would be an identity matrix, and as a result the s matrix will be # given directly by the b_matrix @@ -273,17 +282,36 @@ def test_run_coaxial_component_modeler(monkeypatch, tmp_path): for port_in in modeler.ports: for port_out in modeler.ports: - coords_in = dict(port_in=port_in.name) - coords_out = dict(port_out=port_out.name) + coords_in = {"port_in": port_in.name} + coords_out = {"port_out": port_out.name} assert np.all(s_matrix.sel(**coords_in) != 0), "source index not present in S matrix" - assert np.all( - s_matrix.sel(**coords_in).sel(**coords_out) != 0 - ), "monitor index not present in S matrix" + assert np.all(s_matrix.sel(**coords_in).sel(**coords_out) != 0), ( + "monitor index not present in S matrix" + ) -def test_coarse_grid_at_coaxial_port(monkeypatch, tmp_path): - modeler = make_coaxial_component_modeler(path_dir=str(tmp_path), port_refinement=False) +@pytest.mark.parametrize( + "grid_spec", + [ + None, + td.GridSpec( + grid_x=td.UniformGrid(dl=0.1 * mm), + grid_y=td.UniformGrid(dl=10 * mm), + grid_z=td.UniformGrid(dl=0.1 * mm), + ), + td.GridSpec( + grid_x=td.UniformGrid(dl=10 * mm), + grid_y=td.UniformGrid(dl=0.1 * mm), + grid_z=td.UniformGrid(dl=0.1 * mm), + ), + ], +) +def test_coarse_grid_at_coaxial_port(monkeypatch, tmp_path, grid_spec): + """Ensure that the grid is fine enough at the coaxial ports along the transverse dimensions.""" + modeler = make_coaxial_component_modeler( + path_dir=str(tmp_path), port_refinement=False, grid_spec=grid_spec + ) # Without port refinement the grid is much too coarse for these port sizes with pytest.raises(SetupError): _ = run_component_modeler(monkeypatch, modeler) @@ -376,10 +404,10 @@ def test_power_delivered_helper(monkeypatch, tmp_path): current = np.ones_like(freqs) * current_amplitude def compute_voltage_patch(self, sim_data): - return FreqDataArray(voltage, coords=dict(f=freqs)) + return FreqDataArray(voltage, coords={"f": freqs}) def compute_current_patch(self, sim_data): - return FreqDataArray(current, coords=dict(f=freqs)) + return FreqDataArray(current, coords={"f": freqs}) monkeypatch.setattr(CoaxialLumpedPort, "compute_voltage", compute_voltage_patch) monkeypatch.setattr(CoaxialLumpedPort, "compute_current", compute_current_patch) @@ -452,12 +480,12 @@ def test_run_coaxial_component_modeler_with_wave_ports( shape_both_ports = (len(modeler.freqs),) for port_in in modeler.ports: for port_out in modeler.ports: - coords_in = dict(port_in=port_in.name) - coords_out = dict(port_out=port_out.name) + coords_in = {"port_in": port_in.name} + coords_out = {"port_out": port_out.name} - assert np.all( - s_matrix.sel(**coords_in).values.shape == shape_one_port - ), "source index not present in S matrix" + assert np.all(s_matrix.sel(**coords_in).values.shape == shape_one_port), ( + "source index not present in S matrix" + ) assert np.all( s_matrix.sel(**coords_in).sel(**coords_out).values.shape == shape_both_ports ), "monitor index not present in S matrix" @@ -477,12 +505,12 @@ def test_run_mixed_component_modeler_with_wave_ports(monkeypatch, tmp_path): shape_both_ports = (len(modeler.freqs),) for port_in in modeler.ports: for port_out in modeler.ports: - coords_in = dict(port_in=port_in.name) - coords_out = dict(port_out=port_out.name) + coords_in = {"port_in": port_in.name} + coords_out = {"port_out": port_out.name} - assert np.all( - s_matrix.sel(**coords_in).values.shape == shape_one_port - ), "source index not present in S matrix" + assert np.all(s_matrix.sel(**coords_in).values.shape == shape_one_port), ( + "source index not present in S matrix" + ) assert np.all( s_matrix.sel(**coords_in).sel(**coords_out).values.shape == shape_both_ports ), "monitor index not present in S matrix" @@ -564,6 +592,84 @@ def test_wave_port_path_integral_validation(): current_integral=custom_current_path, ) + # Test integral path only slightly larger than port bounds + wave_port = WavePort( + center=(0, 10000, 115.00000022351743), + size=(500, 0, 160.00000000000003), + name="wave_port_1", + mode_spec=mode_spec, + direction="+", + voltage_integral=voltage_path.updated_copy( + size=(0, 0, 70.000000298023424), center=(0, 10000, 70.000000298023424) + ), + current_integral=None, + ) + # Make sure validation would have failed if a strict comparison was used + assert wave_port.bounds[0][2] > wave_port.voltage_integral.bounds[0][2] + + +def test_wave_port_grid_validation(tmp_path): + """Ensure that 'num_grid_cells' is validated and works to ensure that the grid is refined around wave ports.""" + size_port = [2, 2, 0] + center_port = [0, 0, -10] + + voltage_path = VoltageIntegralAxisAligned( + center=(0.5, 0, -10), + size=(1.0, 0, 0), + extrapolate_to_endpoints=True, + snap_path_to_grid=True, + sign="+", + ) + + current_path = CurrentIntegralAxisAligned( + center=(0.5, 0, -10), + size=(0.25, 0.5, 0), + snap_contour_to_grid=True, + sign="+", + ) + + mode_spec = td.ModeSpec(num_modes=1, target_neff=1.8) + + _ = WavePort( + center=center_port, + size=size_port, + name="wave_port_1", + mode_spec=mode_spec, + direction="+", + voltage_integral=voltage_path, + current_integral=current_path, + num_grid_cells=None, + ) + + with pytest.raises(pd.ValidationError): + _ = WavePort( + center=center_port, + size=size_port, + name="wave_port_1", + mode_spec=mode_spec, + direction="+", + voltage_integral=voltage_path, + current_integral=current_path, + num_grid_cells=2, + ) + + modeler = make_coaxial_component_modeler( + grid_spec=td.GridSpec.auto(wavelength=10e3), + port_refinement=True, + path_dir=str(tmp_path), + port_types=(WavePort, WavePort), + ) + _ = modeler.sim_dict + + modeler = make_coaxial_component_modeler( + grid_spec=td.GridSpec.auto(wavelength=10e3), + port_refinement=False, + path_dir=str(tmp_path), + port_types=(WavePort, WavePort), + ) + with pytest.raises(SetupError): + _ = modeler.sim_dict + def test_wave_port_to_mode_solver(tmp_path): """Checks that wave port can be converted to a mode solver.""" @@ -668,7 +774,7 @@ def test_antenna_helpers(monkeypatch, tmp_path): modeler.get_radiation_monitor_by_name("invalid") # Test monitor data normalization with different amplitude types - a_array = FreqDataArray(np.ones(len(modeler.freqs)), dict(f=modeler.freqs)) + a_array = FreqDataArray(np.ones(len(modeler.freqs)), {"f": modeler.freqs}) normalized_data_array = modeler._monitor_data_at_port_amplitude( modeler.ports[0], sim_data, rad_mon_data, a_array ) diff --git a/tests/test_plugins/test_adjoint.py b/tests/test_plugins/test_adjoint.py index 8cf714c4ba..0bebc2143b 100644 --- a/tests/test_plugins/test_adjoint.py +++ b/tests/test_plugins/test_adjoint.py @@ -1,9 +1,11 @@ """Tests adjoint plugin.""" +from __future__ import annotations + import builtins import time from pathlib import Path -from typing import Dict, List, Tuple +from typing import Optional import gdstk import h5py @@ -13,11 +15,13 @@ import numpy as np import pydantic.v1 as pydantic import pytest -import tidy3d as td import trimesh from jax import grad from jax.test_util import check_grads from numpy.testing import assert_allclose +from xarray import DataArray + +import tidy3d as td from tidy3d.exceptions import AdjointError, DataError, Tidy3dKeyError from tidy3d.plugins.adjoint.components import simulation from tidy3d.plugins.adjoint.components.data.data_array import ( @@ -56,7 +60,6 @@ from tidy3d.plugins.adjoint.web import run, run_async, run_async_local, run_local from tidy3d.plugins.polyslab import ComplexPolySlab from tidy3d.web.api.container import BatchData -from xarray import DataArray from ..test_components.test_custom import CUSTOM_MEDIUM from ..utils import AssertLogLevel, run_async_emulated, run_emulated @@ -157,8 +160,8 @@ def run_emulated_bwd( folder_name: str, callback_url: str, verbose: bool, - num_proc: int = None, - path_dir: str = None, + num_proc: Optional[int] = None, + path_dir: Optional[str] = None, ) -> JaxSimulation: """Runs adjoint simulation on our servers, grabs the gradient data from fwd for processing.""" @@ -200,13 +203,13 @@ def run_emulated_bwd( # Emulated forward and backward run functions def run_async_emulated_fwd( - simulations: Tuple[td.Simulation, ...], - jax_infos: Tuple[JaxInfo, ...], + simulations: tuple[td.Simulation, ...], + jax_infos: tuple[JaxInfo, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, -) -> Tuple[BatchData, Dict[str, str]]: +) -> tuple[BatchData, dict[str, str]]: """Runs the forward simulation on our servers, stores the gradient data for later.""" sim_datas_orig = {} @@ -229,14 +232,14 @@ def run_async_emulated_fwd( def run_async_emulated_bwd( - simulations: Tuple[td.Simulation, ...], - jax_infos: Tuple[JaxInfo, ...], + simulations: tuple[td.Simulation, ...], + jax_infos: tuple[JaxInfo, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, - parent_tasks: List[List[str]], -) -> List[JaxSimulation]: + parent_tasks: list[list[str]], +) -> list[JaxSimulation]: """Runs adjoint simulation on our servers, grabs the gradient data from fwd for processing.""" sim_vjps_orig = [] @@ -259,7 +262,7 @@ def run_async_emulated_bwd( def make_sim( permittivity: float, - size: Tuple[float, float, float], + size: tuple[float, float, float], vertices: tuple, base_eps_val: float, custom_medium: bool = True, @@ -298,12 +301,12 @@ def make_sim( # custom medium Nx, Ny, Nz = 10, 1, 10 (xmin, ymin, zmin), (xmax, ymax, zmax) = jax_box1.bounds - coords = dict( - x=np.linspace(xmin, xmax, Nx).tolist(), - y=np.linspace(ymin, ymax, Ny).tolist(), - z=np.linspace(zmin, zmax, Nz).tolist(), - f=(FREQ0,), - ) + coords = { + "x": np.linspace(xmin, xmax, Nx).tolist(), + "y": np.linspace(ymin, ymax, Ny).tolist(), + "z": np.linspace(zmin, zmax, Nz).tolist(), + "f": (FREQ0,), + } jax_box_custom = JaxBox(size=size, center=(1, 0, 2)) values = base_eps_val + np.random.random((Nx, Ny, Nz, 1)) @@ -571,7 +574,13 @@ def f(permittivity, size, vertices, base_eps_val): def test_adjoint_pipeline_2d(local, use_emulated_run, tmp_path): run_fn = run_local if local else run - sim = make_sim(permittivity=EPS, size=SIZE, vertices=VERTICES, base_eps_val=BASE_EPS_VAL) + sim = make_sim( + permittivity=EPS, + size=SIZE, + vertices=VERTICES, + base_eps_val=BASE_EPS_VAL, + custom_medium=False, + ) sim_size_2d = list(sim.size) sim_size_2d[1] = 0 @@ -581,7 +590,11 @@ def test_adjoint_pipeline_2d(local, use_emulated_run, tmp_path): def f(permittivity, size, vertices, base_eps_val): sim = make_sim( - permittivity=permittivity, size=size, vertices=vertices, base_eps_val=base_eps_val + permittivity=permittivity, + size=size, + vertices=vertices, + base_eps_val=base_eps_val, + custom_medium=False, ) sim_size_2d = list(sim.size) sim_size_2d[1] = 0 @@ -628,10 +641,10 @@ def _test_adjoint_setup_adj(use_emulated_run, tmp_path): for mode_data in sim_data_vjp.output_data: new_values = 0 * np.array(mode_data.amps.values) new_values[0, 0, 0] = 1 + 1j - amps_vjp = mode_data.amps.copy(update=dict(values=new_values.tolist())) - mode_data_vjp = mode_data.copy(update=dict(amps=amps_vjp)) + amps_vjp = mode_data.amps.copy(update={"values": new_values.tolist()}) + mode_data_vjp = mode_data.copy(update={"amps": amps_vjp}) output_data_vjp.append(mode_data_vjp) - sim_data_vjp = sim_data_vjp.copy(update=dict(output_data=output_data_vjp)) + sim_data_vjp = sim_data_vjp.copy(update={"output_data": output_data_vjp}) (sim_vjp,) = run.bwd( task_name="test", folder_name="default", @@ -796,7 +809,7 @@ def test_jax_data_array(): b = [2, 3] c = [4] values = np.random.random((len(a), len(b), len(c))) - coords = dict(a=a, b=b, c=c) + coords = {"a": a, "b": b, "c": c} # validate missing coord # with pytest.raises(AdjointError): @@ -850,7 +863,7 @@ def test_jax_data_array(): with pytest.raises(Tidy3dKeyError): da.interp(d=3) - da1d = JaxDataArray(values=[0.0, 1.0, 2.0, 3.0], coords=dict(x=[0, 1, 2, 3])) + da1d = JaxDataArray(values=[0.0, 1.0, 2.0, 3.0], coords={"x": [0, 1, 2, 3]}) assert np.isclose(da1d.interp(x=0.5), 0.5) # duplicate coordinates @@ -864,7 +877,7 @@ def test_jax_data_array(): c = [4, 6] shape = (len(a), len(b), len(c)) values = np.random.random(shape) - coords = dict(a=a, b=b, c=c) + coords = {"a": a, "b": b, "c": c} da = JaxDataArray(values=values, coords=coords) da2 = da.sel(b=[3, 4]) assert da2.shape == (3, 2, 2) @@ -877,7 +890,7 @@ def test_jax_data_array(): n = 11 cs = list(range(n)) vals = np.random.uniform(0, 1, (n, n, 1, 1, 2)) - coords = dict(x=cs, y=cs, z=[0], f=[0], direction=["+", "-"]) + coords = {"x": cs, "y": cs, "z": [0], "f": [0], "direction": ["+", "-"]} jda = JaxDataArray(values=vals, coords=coords) xda = DataArray(data=vals, coords=coords) @@ -1259,7 +1272,11 @@ def test_adjoint_run_async(local, use_emulated_run_async, tmp_path): def make_sim_simple(permittivity: float) -> JaxSimulation: """Make a sim as a function of a single parameter.""" return make_sim( - permittivity=permittivity, size=SIZE, vertices=VERTICES, base_eps_val=BASE_EPS_VAL + permittivity=permittivity, + size=SIZE, + vertices=VERTICES, + base_eps_val=BASE_EPS_VAL, + custom_medium=False, ) def f(x): @@ -1305,7 +1322,7 @@ def test_diff_data_angles(axis): values = (1 + 1j) * np.random.random((len(ORDERS_X), len(ORDERS_Y), len(FS))) sim_size = [SIZE_2D, SIZE_2D] bloch_vecs = [0, 0] - data = JaxDataArray(values=values, coords=dict(orders_x=ORDERS_X, orders_y=ORDERS_Y, f=FS)) + data = JaxDataArray(values=values, coords={"orders_x": ORDERS_X, "orders_y": ORDERS_Y, "f": FS}) diff_data = JaxDiffractionData( monitor=DIFFRACTION_MONITOR, @@ -1339,7 +1356,7 @@ def test_value_filter(): """Ensure value filter works as expected.""" values = np.array([1, 0.5 * VALUE_FILTER_THRESHOLD, 2 * VALUE_FILTER_THRESHOLD, 0]) - coords = dict(x=list(range(4))) + coords = {"x": list(range(4))} data = JaxDataArray(values=values, coords=coords) values_after, _ = data.nonzero_val_coords @@ -1489,12 +1506,12 @@ def _test_custom_medium_3D(use_emulated_run): def make_custom_medium(Nx: int, Ny: int, Nz: int) -> JaxCustomMedium: # custom medium (xmin, ymin, zmin), (xmax, ymax, zmax) = jax_box.bounds - coords = dict( - x=np.linspace(xmin, xmax, Nx).tolist(), - y=np.linspace(ymin, ymax, Ny).tolist(), - z=np.linspace(zmin, zmax, Nz).tolist(), - f=[FREQ0], - ) + coords = { + "x": np.linspace(xmin, xmax, Nx).tolist(), + "y": np.linspace(ymin, ymax, Ny).tolist(), + "z": np.linspace(zmin, zmax, Nz).tolist(), + "f": [FREQ0], + } values = np.random.random((Nx, Ny, Nz, 1)) eps_ii = JaxDataArray(values=values, coords=coords) @@ -1524,12 +1541,12 @@ def make_custom_medium(num_cells: int) -> JaxCustomMedium: # custom medium (xmin, ymin, zmin), (xmax, ymax, zmax) = jax_box.bounds - coords = dict( - x=np.linspace(xmin, xmax, Nx).tolist(), - y=np.linspace(ymin, ymax, Ny).tolist(), - z=np.linspace(zmin, zmax, Nz).tolist(), - f=[FREQ0], - ) + coords = { + "x": np.linspace(xmin, xmax, Nx).tolist(), + "y": np.linspace(ymin, ymax, Ny).tolist(), + "z": np.linspace(zmin, zmax, Nz).tolist(), + "f": [FREQ0], + } values = np.random.random((Nx, Ny, Nz, 1)) eps_ii = JaxDataArray(values=values, coords=coords) @@ -1559,12 +1576,12 @@ def make_custom_medium(num_cells: int) -> JaxCustomMedium: # custom medium (xmin, ymin, zmin), (xmax, ymax, zmax) = jax_box.bounds - coords = dict( - x=np.linspace(xmin, xmax, Nx).tolist(), - y=np.linspace(ymin, ymax, Ny).tolist(), - z=np.linspace(zmin, zmax, Nz).tolist(), - f=[FREQ0], - ) + coords = { + "x": np.linspace(xmin, xmax, Nx).tolist(), + "y": np.linspace(ymin, ymax, Ny).tolist(), + "z": np.linspace(zmin, zmax, Nz).tolist(), + "f": [FREQ0], + } values = np.random.random((Nx, Ny, Nz, 1)) + 1.0 eps_ii = JaxDataArray(values=values, coords=coords) @@ -1801,10 +1818,8 @@ def test_adjoint_run_time(use_emulated_run, tmp_path, fwidth, run_time, run_time assert sim_adj.run_time == run_time_expected -@pytest.mark.parametrize("has_adj_src, log_level_expected", [(True, None), (False, "WARNING")]) -def test_no_adjoint_sources( - monkeypatch, use_emulated_run, tmp_path, has_adj_src, log_level_expected -): +@pytest.mark.parametrize("has_adj_src", [True, False]) +def test_no_adjoint_sources(monkeypatch, use_emulated_run, tmp_path, has_adj_src): """Make sure warning (not error) if no adjoint sources.""" def make_sim(eps): @@ -1836,8 +1851,9 @@ def make_sim(eps): data = run(sim, task_name="test", path=str(tmp_path / RUN_FILE)) # check whether we got a warning for no sources? - with AssertLogLevel(log_level_expected, contains_str="No adjoint sources"): - data.make_adjoint_simulation(fwidth=src.source_time.fwidth, run_time=sim.run_time) + if not has_adj_src: + with AssertLogLevel("WARNING", contains_str="No adjoint sources"): + data.make_adjoint_simulation(fwidth=src.source_time.fwidth, run_time=sim.run_time) jnp.sum(jnp.abs(jnp.array(data["mnt"].amps.values)) ** 2) @@ -1894,7 +1910,7 @@ def hide_jax(monkeypatch, request): def mocked_import(name, *args, **kwargs): if name in ["jax", "jax.interpreters.ad", "jax.interpreters.ad.JVPTracer"]: - raise ImportError() + raise ImportError return import_orig(name, *args, **kwargs) monkeypatch.setattr(builtins, "__import__", mocked_import) @@ -1951,11 +1967,11 @@ def test_package_flux(): """Test handling of packaging flux data for single and multi-freq.""" value = 1.0 - da_single = JaxDataArray(values=[value], coords=dict(f=[1.0])) + da_single = JaxDataArray(values=[value], coords={"f": [1.0]}) res_single = JaxFieldData.package_flux_results(None, da_single) assert res_single == value - da_multi = JaxDataArray(values=[1.0, 2.0], coords=dict(f=[1.0, 2.0])) + da_multi = JaxDataArray(values=[1.0, 2.0], coords={"f": [1.0, 2.0]}) res_multi = JaxFieldData.package_flux_results(None, da_multi) assert res_multi == da_multi @@ -2022,20 +2038,6 @@ def test_to_gds(tmp_path): polys = sim.to_gdstk(z=0, permittivity_threshold=6, frequency=200e14) assert len(polys) > 0 - # to_gdspy() does not support custom medium - sim = make_sim( - permittivity=EPS, - size=SIZE, - vertices=VERTICES, - base_eps_val=BASE_EPS_VAL, - custom_medium=False, - ) - polys = sim.to_gdspy(z=0) - assert len(polys) > 0 - - polys = sim.to_gdspy(y=0) - assert len(polys) > 4 - @pytest.mark.parametrize( "base_vertices", @@ -2087,13 +2089,13 @@ def sidewall_angle(self, sidewall_angle_deg): return np.deg2rad(sidewall_angle_deg) def test_matches_complexpolyslab(self, vertices, sidewall_angle, dilation): - kwargs = dict( - vertices=vertices, - sidewall_angle=sidewall_angle, - slab_bounds=self.slab_bounds, - dilation=dilation, - axis=POLYSLAB_AXIS, - ) + kwargs = { + "vertices": vertices, + "sidewall_angle": sidewall_angle, + "slab_bounds": self.slab_bounds, + "dilation": dilation, + "axis": POLYSLAB_AXIS, + } cp = ComplexPolySlab(**kwargs) jcp = JaxComplexPolySlab(**kwargs) diff --git a/tests/test_plugins/test_array_factor.py b/tests/test_plugins/test_array_factor.py index fab3ac6d0c..0ca543ea98 100644 --- a/tests/test_plugins/test_array_factor.py +++ b/tests/test_plugins/test_array_factor.py @@ -1,8 +1,11 @@ """Test the array factor functions.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pydantic import pytest + import tidy3d as td import tidy3d.plugins.microwave as mw import tidy3d.plugins.smatrix as smatrix @@ -462,7 +465,7 @@ def test_rectangular_array_calculator_array_make_antenna_array(): ) sim_unit_with_sphere = sim_unit.updated_copy( - structures=[background_sphere] + list(sim_unit.structures) + structures=[background_sphere, *list(sim_unit.structures)] ) # check correctness of the antenna bounds detection antenna_bounds_with_sphere = array_calculator._detect_antenna_bounds(sim_unit_with_sphere) @@ -540,12 +543,12 @@ def test_rectangular_array_calculator_monitor_data_from_array_factor(): far_field_approx=False, ) - coords = dict( - r=[monitor.proj_distance], - theta=list(monitor.theta), - phi=list(monitor.phi), - f=list(monitor.freqs), - ) + coords = { + "r": [monitor.proj_distance], + "theta": list(monitor.theta), + "phi": list(monitor.phi), + "f": list(monitor.freqs), + } values = (1 + 1j) * np.ones( (len(coords["r"]), len(coords["theta"]), len(coords["phi"]), len(coords["f"])) ) @@ -628,12 +631,12 @@ def test_rectangular_array_calculator_monitor_data_from_array_factor(): theta=list(np.linspace(0, np.pi, 10)), far_field_approx=False, ) - coords_under_sampled = dict( - r=[monitor_directivity_under_sampled.proj_distance], - theta=list(monitor_directivity_under_sampled.theta), - phi=list(monitor_directivity_under_sampled.phi), - f=list(monitor_directivity_under_sampled.freqs), - ) + coords_under_sampled = { + "r": [monitor_directivity_under_sampled.proj_distance], + "theta": list(monitor_directivity_under_sampled.theta), + "phi": list(monitor_directivity_under_sampled.phi), + "f": list(monitor_directivity_under_sampled.freqs), + } values_under_sampled = (1 + 1j) * np.random.random( ( len(coords_under_sampled["r"]), @@ -678,12 +681,12 @@ def test_rectangular_array_calculator_simulation_data_from_array_factor(): monitor = sim_unit.monitors[0] monitor_directivity = sim_unit.monitors[2] - coords = dict( - r=[monitor.proj_distance], - theta=list(monitor.theta), - phi=list(monitor.phi), - f=list(monitor.freqs), - ) + coords = { + "r": [monitor.proj_distance], + "theta": list(monitor.theta), + "phi": list(monitor.phi), + "f": list(monitor.freqs), + } values = (1 + 1j) * np.ones( (len(coords["r"]), len(coords["theta"]), len(coords["phi"]), len(coords["f"])) ) diff --git a/tests/test_plugins/test_design.py b/tests/test_plugins/test_design.py index 3e7083cc3b..b35ed5bb84 100644 --- a/tests/test_plugins/test_design.py +++ b/tests/test_plugins/test_design.py @@ -1,21 +1,25 @@ """Test the parameter sweep plugin.""" +from __future__ import annotations + import sys +from typing import Optional import matplotlib.pyplot as plt import numpy as np import pytest + import tidy3d as td import tidy3d.web as web from tidy3d.plugins import design as tdd from ..utils import run_emulated -SWEEP_METHODS = dict( - grid=tdd.MethodGrid(), - monte_carlo=tdd.MethodMonteCarlo(num_points=5, seed=1), - bay_opt=tdd.MethodBayOpt(initial_iter=5, n_iter=2, seed=1), - gen_alg=tdd.MethodGenAlg( +SWEEP_METHODS = { + "grid": tdd.MethodGrid(), + "monte_carlo": tdd.MethodMonteCarlo(num_points=5, seed=1), + "bay_opt": tdd.MethodBayOpt(initial_iter=5, n_iter=2, seed=1), + "gen_alg": tdd.MethodGenAlg( solutions_per_pop=6, n_generations=2, n_parents_mating=4, @@ -23,8 +27,8 @@ mutation_prob=0, keep_parents=0, ), - part_swarm=tdd.MethodParticleSwarm(n_particles=3, n_iter=2, seed=1), -) + "part_swarm": tdd.MethodParticleSwarm(n_particles=3, n_iter=2, seed=1), +} # Task names that should be produced for the different methods expected_task_names = { @@ -36,7 +40,7 @@ } -def emulated_batch_run(simulations, path_dir: str = None, **kwargs): +def emulated_batch_run(simulations, path_dir: Optional[str] = None, **kwargs): data_dict = {task_name: run_emulated(sim) for task_name, sim in simulations.simulations.items()} task_ids = dict(zip(simulations.simulations.keys(), data_dict.keys())) task_paths = {key: f"/path/to/{key}" for key in simulations.simulations.keys()} @@ -800,7 +804,7 @@ def test_result_accessor_and_len(dims, coords, values, multi_val): result = tdd.Result(dims=dims, values=values, coords=coords) - for idx in range(0, len(values)): + for idx in range(len(values)): coord, value = result[idx] assert all(coord == coords[idx]) diff --git a/tests/test_plugins/test_dispersion_fitter.py b/tests/test_plugins/test_dispersion_fitter.py index 0330637bc0..fbdf541c4e 100644 --- a/tests/test_plugins/test_dispersion_fitter.py +++ b/tests/test_plugins/test_dispersion_fitter.py @@ -1,8 +1,16 @@ +from __future__ import annotations + +import io +from unittest import mock + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest import responses +import rich +from rich.progress import Progress + import tidy3d as td from tidy3d.exceptions import SetupError, ValidationError from tidy3d.plugins.dispersion import ( @@ -285,3 +293,37 @@ def test_dispersion_loss_samples(): ep = nAlGaN_mat.eps_model(freq_list) for e in ep: assert e.imag >= 0 + + +def test_dispersion_show_progress(): + eps_real = 2.5 + loss_tangent = 1e-2 + frequency_range = (1e9, 6e9) + + console_out = io.StringIO() + test_console = rich.console.Console(file=console_out, force_terminal=True) + original_init = Progress.__init__ + + def patched_init(self, *args, **kwargs): + kwargs["console"] = test_console + original_init(self, *args, **kwargs) + + with mock.patch("rich.progress.Progress.__init__", patched_init): + mat = FastDispersionFitter.constant_loss_tangent_model( + eps_real, loss_tangent, frequency_range, show_progress=True + ) + + with_progress = console_out.getvalue() + + console_out.truncate(0) + console_out.seek(0) + + mat = FastDispersionFitter.constant_loss_tangent_model( + eps_real, loss_tangent, frequency_range, show_progress=False + ) + without_progress = console_out.getvalue() + + print(with_progress) + print(without_progress) + + assert len(str(with_progress)) > len(str(without_progress)) diff --git a/tests/test_plugins/test_invdes.py b/tests/test_plugins/test_invdes.py index f7c2cc02e0..0cb2a399fb 100644 --- a/tests/test_plugins/test_invdes.py +++ b/tests/test_plugins/test_invdes.py @@ -1,9 +1,11 @@ # Test the inverse design plugin +from __future__ import annotations import autograd.numpy as anp import numpy as np import numpy.testing as npt import pytest + import tidy3d as td import tidy3d.plugins.invdes as tdi from tidy3d.plugins.expressions import ModeAmp, ModePower @@ -361,9 +363,9 @@ def test_continue_run_fns(use_emulated_run): # noqa: F811 num_steps_orig = len(result_orig.history["params"]) num_steps_full = len(result_full.history["params"]) - assert ( - num_steps_full == num_steps_orig + num_steps_continue - ), "wrong number of elements in the combined run history." + assert num_steps_full == num_steps_orig + num_steps_continue, ( + "wrong number of elements in the combined run history." + ) def test_continue_run_from_file(use_emulated_run): # noqa: F811 @@ -377,17 +379,17 @@ def test_continue_run_from_file(use_emulated_run): # noqa: F811 ) num_steps_orig = len(result_orig.history["params"]) num_steps_new = len(result_full.history["params"]) - assert ( - num_steps_new == num_steps_orig + num_steps_continue - ), "wrong number of elements in the combined run history." + assert num_steps_new == num_steps_orig + num_steps_continue, ( + "wrong number of elements in the combined run history." + ) # test the convenience function to load it from file result_full = optimizer.continue_run_from_history(num_steps=2, post_process_fn=post_process_fn) num_steps_orig = num_steps_new num_steps_new = len(result_full.history["params"]) - assert ( - num_steps_new == num_steps_orig + num_steps_continue - ), "wrong number of elements in the combined run history." + assert num_steps_new == num_steps_orig + num_steps_continue, ( + "wrong number of elements in the combined run history." + ) def test_result( @@ -419,7 +421,7 @@ def test_result_data(use_emulated_run, use_emulated_to_sim_data): # noqa: F811 def test_result_data_multi( - use_emulated_to_sim_data, # noqa: F811 + use_emulated_to_sim_data, use_emulated_run, # noqa: F811 tmp_path, ): diff --git a/tests/test_plugins/test_microwave.py b/tests/test_plugins/test_microwave.py index bed13e9698..a769ac700b 100644 --- a/tests/test_plugins/test_microwave.py +++ b/tests/test_plugins/test_microwave.py @@ -1,15 +1,18 @@ """Test the microwave plugin.""" +from __future__ import annotations + from math import isclose import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pd import pytest -import tidy3d as td -import tidy3d.plugins.microwave as mw from skrf import Frequency from skrf.media import MLine + +import tidy3d as td +import tidy3d.plugins.microwave as mw from tidy3d import FieldData from tidy3d.constants import ETA_0 from tidy3d.exceptions import DataError @@ -96,7 +99,7 @@ def make_stripline_scalar_field_data_array(grid_key: str): values = np.where(above_and_within, -ones / ETA_0, values) values = np.where(below_and_within, ones / ETA_0, values) - return td.ScalarFieldDataArray(values, coords=dict(x=XS, y=YS, z=ZS, f=FS)) + return td.ScalarFieldDataArray(values, coords={"x": XS, "y": YS, "z": ZS, "f": FS}) def make_coaxial_field_data_array(grid_key: str): @@ -141,7 +144,7 @@ def compute_coax_radial_electric(rin, rout, x, y, is_x): else: field /= ETA_0 - return td.ScalarFieldDataArray(field, coords=dict(x=XS, y=YS, z=ZS, f=FS)) + return td.ScalarFieldDataArray(field, coords={"x": XS, "y": YS, "z": ZS, "f": FS}) def make_field_data(): @@ -399,7 +402,7 @@ def test_microstrip_models(): freqs = Frequency(start=1, stop=1, npoints=1, unit="ghz") mline = MLine(frequency=freqs, w=width, h=height, t=thickness, ep_r=eps_r, disp="none") - assert np.isclose(Z0, mline.Z0[0]) + assert np.isclose(Z0, mline.z0[0]) assert np.isclose(eps_eff, mline.ep_reff[0]) # Check end effect length computation @@ -411,7 +414,7 @@ def test_microstrip_models(): Z0, eps_eff = mw.models.microstrip.compute_line_params(eps_r, width, height, thickness) mline = MLine(frequency=freqs, w=width, h=height, t=thickness, ep_r=eps_r, disp="none") - assert np.isclose(Z0, mline.Z0[0]) + assert np.isclose(Z0, mline.z0[0]) assert np.isclose(eps_eff, mline.ep_reff[0]) @@ -664,7 +667,7 @@ def test_lobe_measurer_validation(): Urad = np.cos(theta) + 1j * np.sin(theta) # Raise error when radiation pattern is complex - with pytest.raises(pd.ValidationError): + with pytest.raises(pd.ValidationError), pytest.warns(np.exceptions.ComplexWarning): mw.LobeMeasurer( angle=theta, radiation_pattern=Urad, @@ -791,4 +794,3 @@ def test_lobe_plots(min_value): _, ax = plt.subplots(1, 1, subplot_kw={"projection": "polar"}) ax.plot(theta, Urad, "k") lobe_measurer.plot(0, ax) - plt.show() diff --git a/tests/test_plugins/test_mode_solver.py b/tests/test_plugins/test_mode_solver.py index 911916d4b3..9e52ca06ea 100644 --- a/tests/test_plugins/test_mode_solver.py +++ b/tests/test_plugins/test_mode_solver.py @@ -1,8 +1,11 @@ +from __future__ import annotations + import matplotlib.pyplot as plt import numpy as np import pydantic.v1 as pydantic import pytest import responses + import tidy3d as td import tidy3d.plugins.mode.web as msweb from tidy3d import ScalarFieldDataArray @@ -309,6 +312,7 @@ def test_mode_solver_group_index_warning(group_index_step, log_level): mode_spec = td.ModeSpec( num_modes=1, group_index_step=group_index_step, + precision="auto", ) _ = ModeSolver( @@ -457,7 +461,9 @@ def test_mode_solver_custom_medium(mock_remote_api, local, tmp_path): freq0 = td.C_0 / 1.0 n = np.array([1.5, 5]) n = n[:, None, None, None] - n_data = ScalarFieldDataArray(n, coords=dict(x=x_custom, y=y_custom, z=z_custom, f=[freq0])) + n_data = ScalarFieldDataArray( + n, coords={"x": x_custom, "y": y_custom, "z": z_custom, "f": [freq0]} + ) mat_custom = td.CustomMedium.from_nk(n_data, interp_method="nearest") waveguide = td.Structure(geometry=td.Box(size=(100, 0.5, 0.5)), medium=mat_custom) @@ -520,7 +526,7 @@ def test_mode_solver_unstructured_custom_medium(nx, cond_factor, interp, tol, tm n = 2.5 + (x_custom[:, None, None] + 0.6) / 1.2 * np.sin(y_custom[None, :, None]) * np.cos( z_custom[None, None, :] ) - n_data = td.SpatialDataArray(n, coords=dict(x=x_custom, y=y_custom, z=z_custom)) + n_data = td.SpatialDataArray(n, coords={"x": x_custom, "y": y_custom, "z": z_custom}) # unperturbed unstructured grid n_data_u = cartesian_to_unstructured(n_data, pert=0, seed=987, method="direct") @@ -1126,13 +1132,29 @@ def test_modes_eme_sim(mock_remote_api, local): def test_mode_small_bend_radius_fail(): """Test that small bend radius fails.""" - + simulation = td.Simulation( + size=SIM_SIZE, + grid_spec=td.GridSpec(wavelength=1.0), + structures=[WAVEGUIDE], + run_time=1e-12, + symmetry=(1, 0, -1), + boundary_spec=td.BoundarySpec.all_sides(boundary=td.Periodic()), + sources=[SRC], + ) with pytest.raises(ValueError): ms = ModeSolver( plane=PLANE, freqs=np.linspace(1e14, 2e14, 100), mode_spec=td.ModeSpec(num_modes=1, bend_radius=1, bend_axis=0), + simulation=simulation, ) + # should work for infinite mode plane + ms = ModeSolver( + plane=td.Box(center=(0, 0, 0), size=(td.inf, 0, td.inf)), + freqs=np.linspace(1e14, 2e14, 100), + mode_spec=td.ModeSpec(num_modes=1, bend_radius=10000, bend_axis=0), + simulation=simulation, + ) def make_high_order_mode_solver(sign, dim=3): diff --git a/tests/test_plugins/test_polyslab.py b/tests/test_plugins/test_polyslab.py index f62ce47735..267020d36b 100644 --- a/tests/test_plugins/test_polyslab.py +++ b/tests/test_plugins/test_polyslab.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import gdstk import numpy as np + import tidy3d as td from tidy3d.plugins.polyslab import ComplexPolySlab @@ -37,7 +40,7 @@ def test_many_sub_polyslabs(): num_subpoly = 200 dl_list = np.linspace(0, 0.1, num_subpoly) vertices = [(sum(dl_list[: i + 1]), 0) for i in range(num_subpoly)] - vertices = vertices + [(5, 20)] + vertices = [*vertices, (5, 20)] s = ComplexPolySlab( vertices=vertices, diff --git a/tests/test_plugins/test_resonance_finder.py b/tests/test_plugins/test_resonance_finder.py index 3a6f22a87a..2fabe2d3b4 100644 --- a/tests/test_plugins/test_resonance_finder.py +++ b/tests/test_plugins/test_resonance_finder.py @@ -1,6 +1,9 @@ +from __future__ import annotations + import numpy as np import pytest from numpy.random import default_rng + from tidy3d import FieldTimeData, FieldTimeMonitor, ScalarFieldTimeDataArray from tidy3d.plugins.resonance import ResonanceFinder @@ -95,7 +98,7 @@ def test_scalar_field_time(): t = np.arange(NTIME) / time_step signal = generate_signal(freqs, decays, amplitudes, phases, time_step) - coords = dict(x=[0], y=[0], z=[0], t=t) + coords = {"x": [0], "y": [0], "z": [0], "t": t} fd = ScalarFieldTimeDataArray(np.reshape(signal, (1, 1, 1, len(signal))), coords=coords) resonance_finder = ResonanceFinder(freq_window=(0.2, 0.5), init_num_freqs=100) resonances = resonance_finder.run_scalar_field_time(fd) @@ -112,7 +115,7 @@ def test_field_time_single(): t = np.arange(NTIME) / time_step signal = generate_signal(freqs, decays, amplitudes, phases, time_step) - coords = dict(x=[0], y=[0], z=[0], t=t) + coords = {"x": [0], "y": [0], "z": [0], "t": t} fd = ScalarFieldTimeDataArray(np.reshape(signal, (1, 1, 1, len(signal))), coords=coords) fd2 = ScalarFieldTimeDataArray(np.reshape(signal * 2, (1, 1, 1, len(signal))), coords=coords) monitor = FieldTimeMonitor(size=(0, 0, 0), interval=1, name="field", fields=["Hx", "Hy"]) @@ -133,7 +136,7 @@ def test_field_time_mult(): t = np.arange(NTIME) / time_step signal = generate_signal(freqs, decays, amplitudes, phases, time_step) - coords = dict(x=[0], y=[0], z=[0], t=t) + coords = {"x": [0], "y": [0], "z": [0], "t": t} fd = ScalarFieldTimeDataArray(np.reshape(signal, (1, 1, 1, len(signal))), coords=coords) fd2 = ScalarFieldTimeDataArray(np.reshape(signal * 2, (1, 1, 1, len(signal))), coords=coords) monitor = FieldTimeMonitor(size=(0, 0, 0), interval=1, name="field", fields=["Hx", "Hy"]) @@ -155,7 +158,7 @@ def test_field_time_e_and_m(): t = np.arange(NTIME) / time_step signal = generate_signal(freqs, decays, amplitudes, phases, time_step) - coords = dict(x=[0], y=[0], z=[0], t=t) + coords = {"x": [0], "y": [0], "z": [0], "t": t} fd = ScalarFieldTimeDataArray(np.reshape(signal, (1, 1, 1, len(signal))), coords=coords) fd2 = ScalarFieldTimeDataArray(np.reshape(signal * 2, (1, 1, 1, len(signal))), coords=coords) monitor = FieldTimeMonitor(size=(0, 0, 0), interval=1, name="field", fields=["Ex", "Hy"]) @@ -177,7 +180,7 @@ def test_field_time_use_e_only(): t = np.arange(NTIME) / time_step signal = generate_signal(freqs, decays, amplitudes, phases, time_step) - coords = dict(x=[0], y=[0], z=[0], t=t) + coords = {"x": [0], "y": [0], "z": [0], "t": t} fd = ScalarFieldTimeDataArray(np.reshape(signal, (1, 1, 1, len(signal))), coords=coords) fd2 = ScalarFieldTimeDataArray(np.reshape(signal * 2, (1, 1, 1, len(signal))), coords=coords) monitor = FieldTimeMonitor(size=(0, 0, 0), interval=1, name="field", fields=["Hy"]) diff --git a/tests/test_plugins/test_waveguide.py b/tests/test_plugins/test_waveguide.py index 3fcf37ff94..1c84807241 100644 --- a/tests/test_plugins/test_waveguide.py +++ b/tests/test_plugins/test_waveguide.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import numpy as np import pytest -import tidy3d as td from pydantic.v1 import ValidationError + +import tidy3d as td from tidy3d.plugins import waveguide diff --git a/tests/test_web/mock_web.py b/tests/test_web/mock_web.py index 956f00b117..1951088600 100644 --- a/tests/test_web/mock_web.py +++ b/tests/test_web/mock_web.py @@ -1,5 +1,8 @@ # custom class to be the mock return value # will override the requests.Response returned from requests.get +from __future__ import annotations + + class MockResponse: def __init__(self, code, json_data): self.status_code = code diff --git a/tests/test_web/test_cli.py b/tests/test_web/test_cli.py index 6ed6d16d2c..e7cbff4e3d 100644 --- a/tests/test_web/test_cli.py +++ b/tests/test_web/test_cli.py @@ -1,3 +1,6 @@ +from __future__ import annotations + + def test_tidy3d_cli(): pass # if os.path.exists(CONFIG_FILE): diff --git a/tests/test_web/test_env.py b/tests/test_web/test_env.py index 13152cd50b..62e8566b29 100644 --- a/tests/test_web/test_env.py +++ b/tests/test_web/test_env.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import ssl from tidy3d.web.core.environment import Env diff --git a/tests/test_web/test_material_fitter.py b/tests/test_web/test_material_fitter.py index 8f86c001d6..dd52fb3658 100644 --- a/tests/test_web/test_material_fitter.py +++ b/tests/test_web/test_material_fitter.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import pytest import responses + import tidy3d as td from tidy3d.plugins.dispersion import DispersionFitter from tidy3d.web.api.material_fitter import FitterOptions, MaterialFitterTask diff --git a/tests/test_web/test_s3utils.py b/tests/test_web/test_s3utils.py new file mode 100644 index 0000000000..175e860b6d --- /dev/null +++ b/tests/test_web/test_s3utils.py @@ -0,0 +1,122 @@ +from __future__ import annotations + +from unittest.mock import MagicMock + +import pytest + +import tidy3d +from tidy3d.web.core import s3utils + + +@pytest.fixture +def mock_S3STSToken(monkeypatch): + mock_token = MagicMock() + mock_token.cloud_path = "" + mock_token.user_credential = "" + mock_token.get_bucket = lambda: "" + mock_token.get_s3_key = lambda: "" + mock_token.is_expired = lambda: False + mock_token.get_client = lambda: tidy3d.web.core.s3utils.boto3.client() + monkeypatch.setattr( + target=tidy3d.web.core.s3utils, name="_S3STSToken", value=MagicMock(return_value=mock_token) + ) + return mock_token + + +@pytest.fixture +def mock_get_s3_sts_token(monkeypatch): + def _mock_get_s3_sts_token(resource_id, remote_filename): + return s3utils._S3STSToken(resource_id, remote_filename) + + monkeypatch.setattr( + target=tidy3d.web.core.s3utils, name="get_s3_sts_token", value=_mock_get_s3_sts_token + ) + return _mock_get_s3_sts_token + + +@pytest.fixture +def mock_s3_client(monkeypatch): + """ + Fixture that provides a generic mock S3 client. + Method-specific side_effects are omitted here and are specified later in the unit tests. + """ + mock_client = MagicMock() + # Patch the `client` as it is imported within `tidy3d.web.core.s3utils.boto3` so that + # whenever it's invoked (for example with "s3"), it returns our `mock_client`. + monkeypatch.setattr( + target=tidy3d.web.core.s3utils.boto3, + name="client", + value=MagicMock(return_value=mock_client), + ) + return mock_client + + +def test_download_s3_file_success(mock_s3_client, mock_get_s3_sts_token, mock_S3STSToken, tmp_path): + """Tests a successful download.""" + destination_path = tmp_path / "downloaded_file.txt" + expected_content = "abcdefg" + + def simulate_download_success(Bucket, Key, Filename, Callback, Config, **kwargs): + with open(Filename, "w") as f: + f.write(expected_content) + return None + + mock_s3_client.download_file.side_effect = simulate_download_success + mock_S3STSToken.get_bucket = lambda: "test-bucket" + mock_S3STSToken.get_s3_key = lambda: "test-key" + + s3utils.download_file( + resource_id="1234567890", + remote_filename=destination_path.name, + to_file=str(destination_path), + verbose=False, + progress_callback=None, + ) + + # Check that mock_s3_client.download_file() was invoked with the correct arguments. + mock_s3_client.download_file.assert_called_once() + call_args, call_kwargs = mock_s3_client.download_file.call_args + assert call_kwargs["Bucket"] == "test-bucket" + assert call_kwargs["Key"] == "test-key" + assert call_kwargs["Filename"].endswith(s3utils.IN_TRANSIT_SUFFIX) + assert destination_path.exists() + with open(destination_path) as f: + assert f.read() == expected_content + for p in destination_path.parent.iterdir(): + assert not p.name.endswith(s3utils.IN_TRANSIT_SUFFIX) # no temporary files are present + + +def test_download_s3_file_raises_oserror( + mock_s3_client, mock_get_s3_sts_token, mock_S3STSToken, tmp_path +): + """Tests download failing with an ``OSError`` (No space left on device).""" + destination_path = tmp_path / "downloaded_file.txt" + + def simulate_download_failure(Bucket, Key, Filename, Callback, Config, **kwargs): + with open(Filename, "w") as f: + f.write("abc") + raise OSError("No space left on device") + + mock_s3_client.download_file.side_effect = simulate_download_failure + mock_S3STSToken.get_bucket = lambda: "test-bucket" + mock_S3STSToken.get_s3_key = lambda: "test-key" + + with pytest.raises(OSError, match="No space left on device"): + s3utils.download_file( + resource_id="1234567890", + remote_filename=destination_path.name, + to_file=str(destination_path), + verbose=False, + progress_callback=None, + ) + + # Check that mock_s3_client.download_file() was invoked with the correct arguments. + mock_s3_client.download_file.assert_called_once() + call_args, call_kwargs = mock_s3_client.download_file.call_args + assert call_kwargs["Bucket"] == "test-bucket" + assert call_kwargs["Key"] == "test-key" + assert call_kwargs["Filename"].endswith(s3utils.IN_TRANSIT_SUFFIX) + # Since downloading failed, no new files should exist locally. + assert not destination_path.exists() + for p in destination_path.parent.iterdir(): + assert not p.name.endswith(s3utils.IN_TRANSIT_SUFFIX) # no temporary files are present diff --git a/tests/test_web/test_task.py b/tests/test_web/test_task.py index cd2811c36f..dc5c051440 100644 --- a/tests/test_web/test_task.py +++ b/tests/test_web/test_task.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from tidy3d.web.core.task_info import RunInfo diff --git a/tests/test_web/test_tidy3d_folder.py b/tests/test_web/test_tidy3d_folder.py index 280854200b..1846ea8baa 100644 --- a/tests/test_web/test_tidy3d_folder.py +++ b/tests/test_web/test_tidy3d_folder.py @@ -1,7 +1,10 @@ +from __future__ import annotations + import pytest import responses -import tidy3d as td from responses import matchers + +import tidy3d as td from tidy3d.web.core.environment import Env from tidy3d.web.core.task_core import Folder diff --git a/tests/test_web/test_tidy3d_material_library.py b/tests/test_web/test_tidy3d_material_library.py index b897d92962..25790b96dc 100644 --- a/tests/test_web/test_tidy3d_material_library.py +++ b/tests/test_web/test_tidy3d_material_library.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import pytest import responses + import tidy3d as td from tidy3d.web.api.material_libray import MaterialLibray from tidy3d.web.core.environment import Env diff --git a/tests/test_web/test_tidy3d_task.py b/tests/test_web/test_tidy3d_task.py index 6ae348be01..5270964df8 100644 --- a/tests/test_web/test_tidy3d_task.py +++ b/tests/test_web/test_tidy3d_task.py @@ -1,9 +1,12 @@ +from __future__ import annotations + import tempfile import pytest import responses -import tidy3d as td from responses import matchers + +import tidy3d as td from tidy3d.web.core import http_util from tidy3d.web.core.environment import Env, EnvironmentConfig from tidy3d.web.core.task_core import Folder, SimulationTask @@ -215,6 +218,7 @@ def test_submit(set_api_key): "workerGroup": None, "enableCaching": Env.current.enable_caching, "payType": PayType.AUTO, + "priority": None, } ) ], diff --git a/tests/test_web/test_webapi.py b/tests/test_web/test_webapi.py index 1611d046a7..2f63da9d20 100644 --- a/tests/test_web/test_webapi.py +++ b/tests/test_web/test_webapi.py @@ -1,12 +1,13 @@ # Tests webapi and things that depend on it - +from __future__ import annotations import numpy as np import pytest import responses -import tidy3d as td from _pytest import monkeypatch from responses import matchers + +import tidy3d as td from tidy3d import Simulation from tidy3d.__main__ import main from tidy3d.components.data.data_array import ScalarFieldDataArray @@ -85,7 +86,7 @@ def make_sim_data(file_size_gb=FILE_SIZE_GB): src = PointDipole( center=(0, 0, 0), source_time=GaussianPulse(freq0=3e14, fwidth=1e14), polarization="Ex" ) - coords = dict(x=x, y=y, z=z, f=f) + coords = {"x": x, "y": y, "z": z, "f": f} Ex = ScalarFieldDataArray(data, coords=coords) monitor = FieldMonitor(size=(2, 2, 2), freqs=f, name="test", fields=["Ex"]) field_data = FieldData(monitor=monitor, Ex=Ex) @@ -181,29 +182,36 @@ def mock_get_info(monkeypatch, set_api_key): def mock_start(monkeypatch, set_api_key, mock_get_info): """Mocks webapi.start.""" - responses.add( - responses.POST, - f"{Env.current.web_api_endpoint}/tidy3d/tasks/{TASK_ID}/submit", - match=[ - matchers.json_params_matcher( - { - "solverVersion": None, - "workerGroup": None, - "protocolVersion": td.version.__version__, - "enableCaching": Env.current.enable_caching, - "payType": PayType.AUTO, + def add_mock_response(priority=None): + expected_body = { + "solverVersion": None, + "workerGroup": None, + "protocolVersion": td.version.__version__, + "enableCaching": Env.current.enable_caching, + "payType": PayType.AUTO, + "priority": priority, + } + + responses.add( + responses.POST, + f"{Env.current.web_api_endpoint}/tidy3d/tasks/{TASK_ID}/submit", + match=[matchers.json_params_matcher(expected_body)], + json={ + "data": { + "taskId": TASK_ID, + "taskName": TASK_NAME, + "createdAt": CREATED_AT, } - ) - ], - json={ - "data": { - "taskId": TASK_ID, - "taskName": TASK_NAME, - "createdAt": CREATED_AT, - } - }, - status=200, - ) + }, + status=200, + ) + + # Add response for calls without priority + add_mock_response(None) + + # Add responses for calls with specific priority values + for priority in [1, 5, 10]: + add_mock_response(priority) @pytest.fixture @@ -216,9 +224,6 @@ def mock_get_status(task_id): current_status = statuses[current_count] status_count[0] += 1 return current_status - # return TaskInfo( - # status=current_status, taskName=TASK_NAME, taskId=task_id, realFlexUnit=1.0 - # ) run_count = [0] perc_dones = (1, 10, 20, 30, 100) @@ -230,6 +235,8 @@ def mock_get_run_info(task_id): return perc_done, 1 monkeypatch.setattr("tidy3d.web.api.connect_util.REFRESH_TIME", 0.00001) + monkeypatch.setattr(f"{api_path}.REFRESH_TIME", 0.00001) + monkeypatch.setattr("tidy3d.web.api.container.web.REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.RUN_REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.get_status", mock_get_status) monkeypatch.setattr(f"{api_path}.get_run_info", mock_get_run_info) @@ -321,6 +328,39 @@ def test_start(mock_start): start(TASK_ID) +@responses.activate +@pytest.mark.parametrize("priority", [1, 5, 10, None]) +def test_start_with_valid_priority(mock_start, priority): + """Test start with valid priority values.""" + start(TASK_ID, priority=priority) + + +@responses.activate +@pytest.mark.parametrize("priority", [0, -1, 11, 15]) +def test_start_with_invalid_priority(mock_start, priority): + """Test start with invalid priority values.""" + with pytest.raises(ValueError, match="Priority must be between '1' and '10' if specified."): + start(TASK_ID, priority=priority) + + +@responses.activate +@pytest.mark.parametrize("priority", [5, None]) +def test_run_with_valid_priority(mock_webapi, monkeypatch, priority): + """Test run with valid priority parameter.""" + monkeypatch.setattr(f"{api_path}.load", lambda *args, **kwargs: True) + sim = make_sim() + run(sim, TASK_NAME, folder_name=PROJECT_NAME, priority=priority) + + +@responses.activate +@pytest.mark.parametrize("priority", [0, -1, 11, 15]) +def test_run_with_invalid_priority(mock_webapi, priority): + """Test run with invalid priority values.""" + sim = make_sim() + with pytest.raises(ValueError, match="Priority must be between '1' and '10' if specified."): + run(sim, TASK_NAME, folder_name=PROJECT_NAME, priority=priority) + + @responses.activate def test_get_run_info(mock_get_run_info): assert get_run_info(TASK_ID) == (100, 0) @@ -448,60 +488,14 @@ def test_delete_old(set_api_key): json={"data": {"projectId": TASK_ID, "projectName": PROJECT_NAME}}, status=200, ) - - responses.add( - responses.GET, - f"{Env.current.web_api_endpoint}/tidy3d/projects/{TASK_ID}/tasks", - json={"data": [{"taskId": TASK_ID, "createdAt": CREATED_AT}]}, - status=200, - ) - - responses.add( - responses.GET, - f"{Env.current.web_api_endpoint}/tidy3d/tasks/{TASK_ID}", - json={ - "data": { - "taskId": TASK_ID, - "groupId": "group123", - "version": "v1", - "createdAt": CREATED_AT, - } - }, - status=200, - ) - - responses.add( - responses.DELETE, - f"{Env.current.web_api_endpoint}/tidy3d/group/group123/versions", - match=[ - matchers.json_params_matcher( - { - "versions": ["v1"], - } - ) - ], - json={ - "data": { - "taskId": TASK_ID, - "createdAt": CREATED_AT, - } - }, - status=200, - ) - responses.add( responses.DELETE, - f"{Env.current.web_api_endpoint}/tidy3d/tasks/{TASK_ID}", - json={ - "data": { - "taskId": TASK_ID, - "createdAt": CREATED_AT, - } - }, + f"{Env.current.web_api_endpoint}/tidy3d/tasks/{FOLDER_ID}/tasks", + json={"data": 0, "warning": "string"}, status=200, ) - delete_old(100) + delete_old(days_old=100) @responses.activate diff --git a/tests/test_web/test_webapi_account.py b/tests/test_web/test_webapi_account.py index fb00d13e92..bb31a54010 100644 --- a/tests/test_web/test_webapi_account.py +++ b/tests/test_web/test_webapi_account.py @@ -1,7 +1,9 @@ # Tests webapi and things that depend on it +from __future__ import annotations import pytest import responses + import tidy3d as td from tidy3d.web.api.webapi import ( account, diff --git a/tests/test_web/test_webapi_eme.py b/tests/test_web/test_webapi_eme.py index e2053fb58c..fc43f0670d 100644 --- a/tests/test_web/test_webapi_eme.py +++ b/tests/test_web/test_webapi_eme.py @@ -1,10 +1,12 @@ # Tests webapi and things that depend on it +from __future__ import annotations import pytest import responses -import tidy3d as td from botocore.exceptions import ClientError from responses import matchers + +import tidy3d as td from tidy3d import EMESimulation from tidy3d.exceptions import SetupError from tidy3d.web.api.asynchronous import run_async @@ -129,6 +131,7 @@ def mock_start(monkeypatch, set_api_key, mock_get_info): "protocolVersion": td.version.__version__, "enableCaching": Env.current.enable_caching, "payType": PayType.AUTO, + "priority": None, } ) ], @@ -153,9 +156,6 @@ def mock_get_status(task_id): current_status = statuses[current_count] status_count[0] += 1 return current_status - # return TaskInfo( - # status=current_status, taskName=TASK_NAME, taskId=task_id, realFlexUnit=1.0 - # ) run_count = [0] perc_dones = (1, 10, 20, 30, 100) @@ -167,6 +167,8 @@ def mock_get_run_info(task_id): return perc_done, 1 monkeypatch.setattr("tidy3d.web.api.connect_util.REFRESH_TIME", 0.00001) + monkeypatch.setattr(f"{api_path}.REFRESH_TIME", 0.00001) + monkeypatch.setattr("tidy3d.web.api.container.web.REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.RUN_REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.get_status", mock_get_status) monkeypatch.setattr(f"{api_path}.get_run_info", mock_get_run_info) diff --git a/tests/test_web/test_webapi_heat.py b/tests/test_web/test_webapi_heat.py index a691cddc54..15767089e8 100644 --- a/tests/test_web/test_webapi_heat.py +++ b/tests/test_web/test_webapi_heat.py @@ -1,10 +1,12 @@ # Tests webapi and things that depend on it +from __future__ import annotations import pytest import responses -import tidy3d as td from botocore.exceptions import ClientError from responses import matchers + +import tidy3d as td from tidy3d import HeatSimulation from tidy3d.web.api.asynchronous import run_async from tidy3d.web.api.container import Batch, Job @@ -126,6 +128,7 @@ def mock_start(monkeypatch, set_api_key, mock_get_info): "protocolVersion": td.version.__version__, "enableCaching": Env.current.enable_caching, "payType": PayType.AUTO, + "priority": None, } ) ], @@ -150,9 +153,6 @@ def mock_get_status(task_id): current_status = statuses[current_count] status_count[0] += 1 return current_status - # return TaskInfo( - # status=current_status, taskName=TASK_NAME, taskId=task_id, realFlexUnit=1.0 - # ) run_count = [0] perc_dones = (1, 10, 20, 30, 100) @@ -164,6 +164,8 @@ def mock_get_run_info(task_id): return perc_done, 1 monkeypatch.setattr("tidy3d.web.api.connect_util.REFRESH_TIME", 0.00001) + monkeypatch.setattr(f"{api_path}.REFRESH_TIME", 0.00001) + monkeypatch.setattr("tidy3d.web.api.container.web.REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.RUN_REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.get_status", mock_get_status) monkeypatch.setattr(f"{api_path}.get_run_info", mock_get_run_info) @@ -259,7 +261,7 @@ def test_estimate_cost(set_api_key, mock_get_info, mock_metadata): @responses.activate def test_download_json(monkeypatch, mock_get_info, tmp_path): - sim = make_heat_sim() + sim = make_heat_sim(include_custom_source=False) def mock_download(*args, **kwargs): pass @@ -278,7 +280,7 @@ def get_str(*args, **kwargs): @responses.activate def test_load_simulation(monkeypatch, mock_get_info, tmp_path): def mock_download(*args, **kwargs): - make_heat_sim().to_file(args[1]) + make_heat_sim(include_custom_source=False).to_file(args[1]) monkeypatch.setattr(f"{task_core_path}.SimulationTask.get_simulation_json", mock_download) diff --git a/tests/test_web/test_webapi_mode.py b/tests/test_web/test_webapi_mode.py index 432a3fd986..213a9c331a 100644 --- a/tests/test_web/test_webapi_mode.py +++ b/tests/test_web/test_webapi_mode.py @@ -1,11 +1,13 @@ # Tests webapi and things that depend on it +from __future__ import annotations import matplotlib.pyplot as plt import pytest import responses -import tidy3d as td from botocore.exceptions import ClientError from responses import matchers + +import tidy3d as td from tidy3d.components.data.dataset import ModeIndexDataArray from tidy3d.plugins.mode import ModeSolver from tidy3d.web.api.asynchronous import run_async @@ -106,11 +108,22 @@ def mock_upload(monkeypatch, set_api_key): status=200, ) + # store the uploaded stub for verification + uploaded_stub = {} + + def mock_upload_simulation(self, stub, **kwargs): + uploaded_stub["stub"] = stub + def mock_upload_file(*args, **kwargs): pass + monkeypatch.setattr( + "tidy3d.web.core.task_core.SimulationTask.upload_simulation", mock_upload_simulation + ) monkeypatch.setattr("tidy3d.web.core.task_core.upload_file", mock_upload_file) + return uploaded_stub + @pytest.fixture def mock_get_info(monkeypatch, set_api_key): @@ -151,6 +164,7 @@ def mock_start(monkeypatch, set_api_key, mock_get_info): "protocolVersion": td.version.__version__, "enableCaching": Env.current.enable_caching, "payType": PayType.AUTO, + "priority": None, } ) ], @@ -175,9 +189,6 @@ def mock_get_status(task_id): current_status = statuses[current_count] status_count[0] += 1 return current_status - # return TaskInfo( - # status=current_status, taskName=TASK_NAME, taskId=task_id, realFlexUnit=1.0 - # ) run_count = [0] perc_dones = (1, 10, 20, 30, 100) @@ -189,6 +200,8 @@ def mock_get_run_info(task_id): return perc_done, 1 monkeypatch.setattr("tidy3d.web.api.connect_util.REFRESH_TIME", 0.00001) + monkeypatch.setattr(f"{api_path}.REFRESH_TIME", 0.00001) + monkeypatch.setattr("tidy3d.web.api.container.web.REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.RUN_REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.get_status", mock_get_status) monkeypatch.setattr(f"{api_path}.get_run_info", mock_get_run_info) @@ -267,6 +280,26 @@ def test_upload(monkeypatch, mock_upload, mock_get_info, mock_metadata): assert upload(sim, TASK_NAME, PROJECT_NAME, reduce_simulation=True) +@pytest.mark.parametrize("reduce_simulation", [True, False]) +@responses.activate +def test_upload_with_reduction_parameter( + monkeypatch, mock_upload, mock_get_info, mock_metadata, reduce_simulation +): + """Test that simulation reduction is properly applied before upload based on reduce_simulation parameter.""" + sim = make_mode_sim() + + upload(sim, TASK_NAME, PROJECT_NAME, reduce_simulation=reduce_simulation) + + if reduce_simulation: + expected_sim = get_reduced_simulation(sim, reduce_simulation=True) + assert sim != expected_sim + else: + expected_sim = sim + + uploaded_sim = mock_upload["stub"].simulation + assert uploaded_sim == expected_sim + + @responses.activate def test_get_info(mock_get_info): assert get_info(TASK_ID).taskId == TASK_ID diff --git a/tests/test_web/test_webapi_mode_sim.py b/tests/test_web/test_webapi_mode_sim.py index 381f409287..275d204a9f 100644 --- a/tests/test_web/test_webapi_mode_sim.py +++ b/tests/test_web/test_webapi_mode_sim.py @@ -1,10 +1,12 @@ # Tests webapi and things that depend on it +from __future__ import annotations import pytest import responses -import tidy3d as td from botocore.exceptions import ClientError from responses import matchers + +import tidy3d as td from tidy3d.plugins.mode import ModeSolver from tidy3d.web.api.asynchronous import run_async from tidy3d.web.api.container import Batch, Job @@ -102,11 +104,22 @@ def mock_upload(monkeypatch, set_api_key): status=200, ) + # store the uploaded stub for verification + uploaded_stub = {} + + def mock_upload_simulation(self, stub, **kwargs): + uploaded_stub["stub"] = stub + def mock_upload_file(*args, **kwargs): pass + monkeypatch.setattr( + "tidy3d.web.core.task_core.SimulationTask.upload_simulation", mock_upload_simulation + ) monkeypatch.setattr("tidy3d.web.core.task_core.upload_file", mock_upload_file) + return uploaded_stub + @pytest.fixture def mock_get_info(monkeypatch, set_api_key): @@ -147,6 +160,7 @@ def mock_start(monkeypatch, set_api_key, mock_get_info): "protocolVersion": td.version.__version__, "enableCaching": Env.current.enable_caching, "payType": PayType.AUTO, + "priority": None, } ) ], @@ -171,9 +185,6 @@ def mock_get_status(task_id): current_status = statuses[current_count] status_count[0] += 1 return current_status - # return TaskInfo( - # status=current_status, taskName=TASK_NAME, taskId=task_id, realFlexUnit=1.0 - # ) run_count = [0] perc_dones = (1, 10, 20, 30, 100) @@ -185,6 +196,8 @@ def mock_get_run_info(task_id): return perc_done, 1 monkeypatch.setattr("tidy3d.web.api.connect_util.REFRESH_TIME", 0.00001) + monkeypatch.setattr(f"{api_path}.REFRESH_TIME", 0.00001) + monkeypatch.setattr("tidy3d.web.api.container.web.REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.RUN_REFRESH_TIME", 0.00001) monkeypatch.setattr(f"{api_path}.get_status", mock_get_status) monkeypatch.setattr(f"{api_path}.get_run_info", mock_get_run_info) @@ -263,6 +276,26 @@ def test_upload(monkeypatch, mock_upload, mock_get_info, mock_metadata): assert upload(sim, TASK_NAME, PROJECT_NAME, reduce_simulation=True) +@pytest.mark.parametrize("reduce_simulation", [True, False]) +@responses.activate +def test_upload_with_reduction_parameter( + monkeypatch, mock_upload, mock_get_info, mock_metadata, reduce_simulation +): + """Test that simulation reduction is properly applied before upload based on reduce_simulation parameter.""" + sim = make_mode_sim() + + upload(sim, TASK_NAME, PROJECT_NAME, reduce_simulation=reduce_simulation) + + if reduce_simulation: + expected_sim = get_reduced_simulation(sim, reduce_simulation=True) + assert sim != expected_sim + else: + expected_sim = sim + + uploaded_sim = mock_upload["stub"].simulation + assert uploaded_sim == expected_sim + + @responses.activate def test_get_info(mock_get_info): assert get_info(TASK_ID).taskId == TASK_ID diff --git a/tests/utils.py b/tests/utils.py index d09ab640a8..767ebb4684 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,14 +1,17 @@ +from __future__ import annotations + import dataclasses from pathlib import Path -from typing import Any, Dict, List, Tuple, Union +from typing import Any, Optional, Union import numpy as np import pydantic.v1 as pd -import tidy3d as td import trimesh import xarray as xr from autograd.core import VJPNode from autograd.tracer import new_box + +import tidy3d as td from tidy3d import ModeIndexDataArray from tidy3d.components.base import Tidy3dBaseModel from tidy3d.log import _get_level_int @@ -54,7 +57,7 @@ def cartesian_to_unstructured( array: td.SpatialDataArray, pert: float = 0.1, method: str = "linear", - seed: int = None, + seed: Optional[int] = None, same_bounds: bool = True, ) -> Union[td.TriangularGridDataset, td.TetrahedralGridDataset]: """Convert a SpatialDataArray into TriangularGridDataset/TetrahedralGridDataset with @@ -262,18 +265,18 @@ def make_spatial_data( data = lims[0] + (lims[1] - lims[0]) * rng.random(size) arr = td.SpatialDataArray( data, - coords=dict( - x=np.linspace(bounds[0][0], bounds[1][0], size[0]), - y=np.linspace(bounds[0][1], bounds[1][1], size[1]), - z=np.linspace(bounds[0][2], bounds[1][2], size[2]), - ), + coords={ + "x": np.linspace(bounds[0][0], bounds[1][0], size[0]), + "y": np.linspace(bounds[0][1], bounds[1][1], size[1]), + "z": np.linspace(bounds[0][2], bounds[1][2], size[2]), + }, ) if unstructured: return cartesian_to_unstructured(arr, pert=perturbation, method=method, seed=seed_grid) return arr -COORDS = dict(x=[-1.5, -0.5], y=[0, 1], z=[0, 1]) +COORDS = {"x": [-1.5, -0.5], "y": [0, 1], "z": [0, 1]} CUSTOM_SIZE = (2, 2, 2) CUSTOM_BOUNDS = [[-1.5, 0, 0], [-0.5, 1, 1]] CUSTOM_GRID_SEED = 12345 @@ -420,7 +423,7 @@ def make_custom_data(lims, unstructured): slab_bounds=(-0.1, 0.1), ), medium=td.CustomMedium( - permittivity=td.SpatialDataArray(tracer_arr, coords=dict(x=[-1], y=[0], z=[0])) + permittivity=td.SpatialDataArray(tracer_arr, coords={"x": [-1], "y": [0], "z": [0]}) ), name="traced custom polyslab", ), @@ -471,6 +474,10 @@ def make_custom_data(lims, unstructured): geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), medium=td.AnisotropicMedium(xx=td.PEC, yy=td.Medium(), zz=td.Medium()), ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), + medium=td.AnisotropicMedium(xx=td.PMC, yy=td.Medium(), zz=td.Medium()), + ), # Test a fully anistropic medium td.Structure( geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), @@ -482,6 +489,10 @@ def make_custom_data(lims, unstructured): medium=td.PEC, name="pec_group", ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(-1, 0, 0)), + medium=td.PMC, + ), td.Structure( geometry=td.Cylinder(radius=1.0, length=2.0, center=(1.0, 0.0, -1.0), axis=1), medium=td.AnisotropicMedium( @@ -664,6 +675,14 @@ def make_custom_data(lims, unstructured): medium=td.Medium(permittivity=1.5), name="transformed_box", ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(1, 1, 1)), + medium=td.MultiPhysicsMedium( + optical=td.Medium(permittivity=4.0), + charge=td.ChargeInsulatorMedium(permittivity=2), + name="SiO2", + ), + ), ], sources=[ td.UniformCurrentSource( @@ -733,12 +752,12 @@ def make_custom_data(lims, unstructured): field_dataset=td.FieldDataset( Ex=td.ScalarFieldDataArray( np.ones((101, 101, 1, 1)), - coords=dict( - x=np.linspace(-1, 1, 101), - y=np.linspace(-1, 1, 101), - z=np.array([0]), - f=[2e14], - ), + coords={ + "x": np.linspace(-1, 1, 101), + "y": np.linspace(-1, 1, 101), + "z": np.array([0]), + "f": [2e14], + }, ) ), ), @@ -752,12 +771,12 @@ def make_custom_data(lims, unstructured): current_dataset=td.FieldDataset( Ex=td.ScalarFieldDataArray( np.ones((101, 101, 1, 1)), - coords=dict( - x=np.linspace(-1, 1, 101), - y=np.linspace(-1, 1, 101), - z=np.array([0]), - f=[2e14], - ), + coords={ + "x": np.linspace(-1, 1, 101), + "y": np.linspace(-1, 1, 101), + "z": np.array([0]), + "f": [2e14], + }, ) ), ), @@ -899,6 +918,208 @@ def make_custom_data(lims, unstructured): ) +FULL_STEADY_HEAT = td.HeatChargeSimulation( + center=(0, 0, 0), + size=(2, 2, 2), + medium=td.MultiPhysicsMedium( + heat=td.FluidMedium(), charge=td.ChargeInsulatorMedium(), name="air" + ), + structures=[ + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(0, 1, 0)), + medium=td.MultiPhysicsMedium( + heat=td.FluidMedium(), charge=td.ChargeInsulatorMedium(), name="temperature0_box" + ), + name="temperature0_box", + ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(0, -1, 0)), + medium=td.MultiPhysicsMedium( + heat=td.FluidMedium(), charge=td.ChargeInsulatorMedium(), name="temperature1_box" + ), + name="temperature1_box", + ), + td.Structure( + geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)), + medium=td.MultiPhysicsMedium( + heat=td.SolidMedium.from_si_units(conductivity=1.0, capacity=1.0, density=1.0), + charge=td.ChargeConductorMedium(conductivity=1.0), + name="solid_box", + ), + name="solid_box", + ), + ], + boundary_spec=[ + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["temperature0_box", "solid_box"]), + condition=td.TemperatureBC(temperature=300.0), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["temperature1_box", "solid_box"]), + condition=td.TemperatureBC(temperature=320.0), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["air", "solid_box"]), + condition=td.HeatFluxBC(flux=0.0), + ), + ], + monitors=[ + td.TemperatureMonitor( + center=(0, 0, 0), + size=(1, 1, 1), + unstructured=True, + name="temperature_monitor", + ) + ], + sources=[td.HeatSource(rate=1.0, structures=["solid_box"])], + grid_spec=td.UniformUnstructuredGrid(dl=0.05), + symmetry=(1, 0, 0), +) + +FULL_UNSTEADY_HEAT = FULL_STEADY_HEAT.updated_copy( + analysis_spec=td.UnsteadyHeatAnalysis( + initial_temperature=300.0, + unsteady_spec=td.UnsteadySpec(time_step=1e-3, total_time_steps=1000), + ) +) + + +FULL_CONDUCTION = FULL_STEADY_HEAT.updated_copy( + monitors=[ + td.SteadyPotentialMonitor( + center=(0, 0, 0), size=(1, 1, 1), name="potential_monitor", unstructured=True + ), + ], + boundary_spec=[ + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["temperature0_box", "solid_box"]), + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=5.0)), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["temperature1_box", "solid_box"]), + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0.0)), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["air", "solid_box"]), + condition=td.InsulatingBC(), + ), + ], + sources=[], +) + + +FULL_SEMICONDUCTOR = td.SemiconductorMedium( + permittivity=11, + N_d=0, + N_a=0, + N_c=2e19, + N_v=2e19, + E_g=1.0, + mobility_n=td.ConstantMobilityModel(mu=1500), + mobility_p=td.CaugheyThomasMobility( + mu_min=44.9, + mu=470.5, + ref_N=2.23e17, + exp_N=0.719, + exp_1=-0.57, + exp_2=-2.33, + exp_3=2.4, + exp_4=-0.146, + ), + R=[ + td.ShockleyReedHallRecombination(tau_n=3.3e-6, tau_p=4e-6), + td.RadiativeRecombination(r_const=1.6e-14), + td.AugerRecombination(c_n=2.8e-31, c_p=9.9e-32), + ], + delta_E_g=td.SlotboomBandGapNarrowing( + v1=6.92e-3, + n2=1.3e17, + c2=0.5, + min_N=1e15, + ), +) + +FULL_CHARGE = td.HeatChargeSimulation( + center=(0, 0, 0), + size=(3, 3, 0), + medium=td.MultiPhysicsMedium( + charge=td.ChargeInsulatorMedium(), heat=td.FluidMedium(), name="air" + ), + structures=[ + # oxide + td.Structure( + geometry=td.Box(center=(0, 0, 0), size=(1.999, 2, 1)), + medium=td.MultiPhysicsMedium( + heat=td.SolidMedium(conductivity=1.0, capacity=1.0, density=1.0), name="oxide" + ), + ), + # p-side + td.Structure( + geometry=td.Box(center=(-0.5, 0, 0), size=(1, 1, 1)), + medium=FULL_SEMICONDUCTOR.updated_copy(N_a=1e18, name="p_side"), + ), + # n-side + td.Structure( + geometry=td.Box(center=(0.5, 0, 0), size=(1, 1, 1)), + medium=FULL_SEMICONDUCTOR.updated_copy(N_d=1e18, name="n_side"), + ), + ], + boundary_spec=[ + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["p_side", "air"]), + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=[-0.5, 0.0, 1])), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["n_side", "air"]), + condition=td.VoltageBC(source=td.DCVoltageSource(voltage=0.0)), + ), + td.HeatChargeBoundarySpec( + placement=td.MediumMediumInterface(mediums=["oxide", "air"]), + condition=td.InsulatingBC(), + ), + ], + monitors=[ + td.SteadyFreeCarrierMonitor( + center=(0, 0, 0), + size=(1, 1, 1), + name="free_carrier_monitor", + unstructured=True, + ), + td.SteadyPotentialMonitor( + center=(0, 0, 0), + size=(1, 1, 1), + name="potential_monitor", + unstructured=True, + ), + td.SteadyCapacitanceMonitor( + center=(0, 0, 0), + size=(1, 1, 1), + name="capacitance_monitor", + unstructured=True, + ), + ], + analysis_spec=td.IsothermalSteadyChargeDCAnalysis( + temperature=300.0, + convergence_dv=0.1, + fermi_dirac=False, + tolerance_settings=td.ChargeToleranceSpec( + rel_tol=1e-4, + abs_tol=1e6, + max_iters=400, + ), + ), + grid_spec=td.UniformUnstructuredGrid(dl=0.05, relative_min_dl=0), +) + +SAMPLE_SIMULATIONS = { + "full_fdtd": SIM_FULL, + "full_steady_heat": FULL_STEADY_HEAT, + "full_unsteady_heat": FULL_UNSTEADY_HEAT, + "full_conduction": FULL_CONDUCTION, + "full_charge": FULL_CHARGE, +} + + def get_spatial_coords_dict(simulation: td.Simulation, monitor: td.Monitor, field_name: str): """Returns MonitorData coordinates associated with a Monitor object""" grid = simulation.discretize_monitor(monitor) @@ -919,7 +1140,7 @@ def get_spatial_coords_dict(simulation: td.Simulation, monitor: td.Monitor, fiel def run_emulated(simulation: td.Simulation, path=None, **kwargs) -> td.SimulationData: """Emulates a simulation run.""" - from scipy.ndimage.filters import gaussian_filter + from scipy.ndimage import gaussian_filter x = kwargs.get("x0", 1.0) @@ -1025,10 +1246,10 @@ def make_diff_data(monitor: td.DiffractionMonitor) -> td.DiffractionData: f = list(monitor.freqs) orders_x = np.linspace(-1, 1, 3) orders_y = np.linspace(-2, 2, 5) - coords = dict(orders_x=orders_x, orders_y=orders_y, f=f) + coords = {"orders_x": orders_x, "orders_y": orders_y, "f": f} values = DATA_GEN_FN((len(orders_x), len(orders_y), len(f))) data = td.DiffractionDataArray(values, coords=coords) - field_data = {field: data for field in ("Er", "Etheta", "Ephi", "Hr", "Htheta", "Hphi")} + field_data = dict.fromkeys(("Er", "Etheta", "Ephi", "Hr", "Htheta", "Hphi"), data) return td.DiffractionData(monitor=monitor, sim_size=(1, 1), bloch_vecs=(0, 0), **field_data) def make_mode_data(monitor: td.ModeMonitor) -> td.ModeData: @@ -1040,7 +1261,7 @@ def make_mode_data(monitor: td.ModeMonitor) -> td.ModeData: n_complex = make_data( coords=index_coords, data_array_type=td.ModeIndexDataArray, is_complex=True ) - coords_amps = dict(direction=["+", "-"]) + coords_amps = {"direction": ["+", "-"]} coords_amps.update(index_coords) amps = make_data(coords=coords_amps, data_array_type=td.ModeAmpsDataArray, is_complex=True) field_cmps = {} @@ -1063,7 +1284,7 @@ def make_mode_data(monitor: td.ModeMonitor) -> td.ModeData: def make_flux_data(monitor: td.FluxMonitor) -> td.FluxData: """make a random ModeData from a ModeMonitor.""" - coords = dict(f=list(monitor.freqs)) + coords = {"f": list(monitor.freqs)} flux = make_data(coords=coords, data_array_type=td.FluxDataArray, is_complex=False) return td.FluxData(monitor=monitor, flux=flux) @@ -1074,9 +1295,9 @@ def make_directivity_data(monitor: td.DirectivityMonitor) -> td.DirectivityData: r = np.atleast_1d(monitor.proj_distance) theta = list(monitor.theta) phi = list(monitor.phi) - fluxcoords = dict(f=f) + fluxcoords = {"f": f} fluxdata = make_data(coords=fluxcoords, data_array_type=td.FluxDataArray, is_complex=False) - coords = dict(r=r, theta=theta, phi=phi, f=f) + coords = {"r": r, "theta": theta, "phi": phi, "f": f} scalar_field = make_data( coords=coords, data_array_type=td.FieldProjectionAngleDataArray, is_complex=True ) @@ -1101,7 +1322,7 @@ def make_field_projection_angle_data( theta = list(monitor.theta) phi = list(monitor.phi) - coords = dict(r=r, theta=theta, phi=phi, f=f) + coords = {"r": r, "theta": theta, "phi": phi, "f": f} scalar_field = make_data( coords=coords, data_array_type=td.FieldProjectionAngleDataArray, @@ -1133,26 +1354,26 @@ def make_field_projection_cartesian_data( # map the two planes to global (x, y, z) depending on the normal axis if monitor.proj_axis == 0: # (y, z) - coords = dict( - x=np.atleast_1d(proj_distance), - y=x_plane, - z=y_plane, - f=f, - ) + coords = { + "x": np.atleast_1d(proj_distance), + "y": x_plane, + "z": y_plane, + "f": f, + } elif monitor.proj_axis == 1: # (x, z) - coords = dict( - x=x_plane, - y=np.atleast_1d(proj_distance), - z=y_plane, - f=f, - ) + coords = { + "x": x_plane, + "y": np.atleast_1d(proj_distance), + "z": y_plane, + "f": f, + } else: # (x, y) - coords = dict( - x=x_plane, - y=y_plane, - z=np.atleast_1d(proj_distance), - f=f, - ) + coords = { + "x": x_plane, + "y": y_plane, + "z": np.atleast_1d(proj_distance), + "f": f, + } scalar_field = make_data( coords=coords, @@ -1180,7 +1401,7 @@ def make_field_projection_kspace_data( ux = list(monitor.ux) uy = list(monitor.uy) - coords = dict(ux=ux, uy=uy, r=r, f=f) + coords = {"ux": ux, "uy": uy, "r": r, "f": f} scalar_field = make_data( coords=coords, data_array_type=td.FieldProjectionKSpaceDataArray, @@ -1224,17 +1445,17 @@ def make_field_projection_kspace_data( class BatchDataTest(Tidy3dBaseModel): """Holds a collection of :class:`.SimulationData` returned by :class:`.Batch`.""" - task_paths: Dict[str, str] = pd.Field( + task_paths: dict[str, str] = pd.Field( ..., title="Data Paths", description="Mapping of task_name to path to corresponding data for each task in batch.", ) - task_ids: Dict[str, str] = pd.Field( + task_ids: dict[str, str] = pd.Field( ..., title="Task IDs", description="Mapping of task_name to task_id for each task in batch." ) - sim_data: Dict[str, td.SimulationData] + sim_data: dict[str, td.SimulationData] def load_sim_data(self, task_name: str) -> td.SimulationData: """Load a :class:`.SimulationData` from file by task name.""" @@ -1242,7 +1463,7 @@ def load_sim_data(self, task_name: str) -> td.SimulationData: _ = self.task_ids[task_name] return self.sim_data[task_name] - def items(self) -> Tuple[str, td.SimulationData]: + def items(self) -> tuple[str, td.SimulationData]: """Iterate through the :class:`.SimulationData` for each task_name.""" for task_name in self.task_paths.keys(): yield task_name, self.load_sim_data(task_name) @@ -1252,17 +1473,17 @@ def __getitem__(self, task_name: str) -> td.SimulationData: return self.load_sim_data(task_name) -def run_async_emulated(simulations: Dict[str, td.Simulation], **kwargs) -> BatchData: +def run_async_emulated(simulations: dict[str, td.Simulation], **kwargs) -> BatchData: """Emulate an async run function.""" task_ids = {task_name: f"task_id={i}" for i, task_name in enumerate(simulations.keys())} - task_paths = {task_name: "NONE" for task_name in simulations.keys()} + task_paths = dict.fromkeys(simulations.keys(), "NONE") sim_data = {task_name: run_emulated(sim) for task_name, sim in simulations.items()} return BatchDataTest(task_paths=task_paths, task_ids=task_ids, sim_data=sim_data) def assert_log_level( - records: List[Tuple[int, str]], log_level_expected: str, contains_str: str = None + records: list[tuple[int, str]], log_level_expected: str, contains_str: Optional[str] = None ) -> None: """Testing tool: Raises error if a log was not recorded as expected. diff --git a/tidy3d/__init__.py b/tidy3d/__init__.py index b1f57f7f34..b5310ed9d1 100644 --- a/tidy3d/__init__.py +++ b/tidy3d/__init__.py @@ -1,5 +1,7 @@ """Tidy3d package imports""" +from __future__ import annotations + from tidy3d.components.material.multi_physics import MultiPhysicsMedium from tidy3d.components.material.tcad.charge import ( ChargeConductorMedium, @@ -21,17 +23,21 @@ ) from tidy3d.components.spice.sources.dc import DCCurrentSource, DCVoltageSource from tidy3d.components.spice.sources.types import VoltageSourceType +from tidy3d.components.tcad.analysis.heat_simulation_type import UnsteadyHeatAnalysis, UnsteadySpec from tidy3d.components.tcad.boundary.specification import ( HeatBoundarySpec, HeatChargeBoundarySpec, ) +from tidy3d.components.tcad.data.monitor_data.mesh import VolumeMeshData from tidy3d.components.tcad.data.sim_data import ( DeviceCharacteristics, HeatChargeSimulationData, HeatSimulationData, + VolumeMesherData, ) from tidy3d.components.tcad.data.types import ( SteadyCapacitanceData, + SteadyElectricFieldData, SteadyEnergyBandData, SteadyFreeCarrierData, SteadyPotentialData, @@ -45,15 +51,16 @@ GridRefinementRegion, UniformUnstructuredGrid, ) +from tidy3d.components.tcad.mesher import VolumeMesher from tidy3d.components.tcad.monitors.charge import ( SteadyCapacitanceMonitor, + SteadyElectricFieldMonitor, SteadyEnergyBandMonitor, SteadyFreeCarrierMonitor, SteadyPotentialMonitor, ) -from tidy3d.components.tcad.monitors.heat import ( - TemperatureMonitor, -) +from tidy3d.components.tcad.monitors.heat import TemperatureMonitor +from tidy3d.components.tcad.monitors.mesh import VolumeMeshMonitor from tidy3d.components.tcad.simulation.heat import HeatSimulation from tidy3d.components.tcad.simulation.heat_charge import HeatChargeSimulation from tidy3d.components.tcad.types import ( @@ -131,6 +138,8 @@ FluxTimeDataArray, HeatDataArray, IndexedDataArray, + IndexedFieldVoltageDataArray, + IndexedTimeDataArray, IndexedVoltageDataArray, ModeAmpsDataArray, ModeIndexDataArray, @@ -235,6 +244,7 @@ from .components.medium import ( PEC, PEC2D, + PMC, AbstractMedium, AnisotropicMedium, CustomAnisotropicMedium, @@ -260,6 +270,7 @@ PECMedium, PerturbationMedium, PerturbationPoleResidue, + PMCMedium, PoleResidue, Sellmeier, SurfaceImpedanceFitterParam, @@ -328,6 +339,7 @@ ModeSource, PlaneWave, ) +from .components.source.freq_range import FreqRange # sources from .components.source.time import ( @@ -360,7 +372,7 @@ SpaceTimeModulation, ) from .components.transformation import RotationAroundAxis -from .components.viz import VisualizationSpec +from .components.viz import VisualizationSpec, restore_matplotlib_rcparams # config from .config import config @@ -396,296 +408,310 @@ def set_logging_level(level: str) -> None: GeometryGroup.update_forward_refs() __all__ = [ - "Grid", - "Coords", - "GridSpec", - "UniformGrid", - "QuasiUniformGrid", - "CustomGrid", + "C_0", + "DATA_TYPE_MAP", + "EPSILON_0", + "ETA_0", + "HBAR", + "K_B", + "MU_0", + "PEC", + "PEC2D", + "PMC", + "PML", + "TFSF", + "Absorber", + "AbsorberParams", + "AbstractFieldProjectionData", + "AbstractMedium", + "AdmittanceNetwork", + "AnisotropicMedium", + "AntennaMetricsData", + "ApodizationSpec", + "AstigmaticGaussianBeam", + "AstigmaticGaussianBeamProfile", + "AugerRecombination", "AutoGrid", - "CustomGridBoundaries", - "LayerRefinementSpec", - "GridRefinement", - "CornerFinderSpec", + "AuxFieldTimeData", + "AuxFieldTimeMonitor", + "BlochBoundary", + "Boundary", + "BoundaryEdge", + "BoundaryEdgeType", + "BoundarySpec", "Box", - "Sphere", - "Cylinder", - "PolySlab", - "GeometryGroup", + "CaugheyThomasMobility", + "CellDataArray", + "ChargeConductorMedium", + "ChargeDataArray", + "ChargeInsulatorMedium", + "ChargeToleranceSpec", "ClipOperation", - "Transformed", - "TriangleMesh", - "Medium", - "PoleResidue", - "AnisotropicMedium", - "PEC", - "PECMedium", - "Medium2D", - "PEC2D", - "Sellmeier", - "Debye", - "Drude", - "Lorentz", + "CoaxialLumpedResistor", + "ConstantDoping", + "ConstantMobilityModel", + "ContinuousWave", + "ContinuousWaveTimeModulation", + "ContourPathAveraging", + "ConvectionBC", + "Coords", + "Coords1D", + "CornerFinderSpec", + "CurrentBC", + "CustomAnisotropicMedium", + "CustomChargePerturbation", + "CustomCurrentSource", + "CustomDebye", + "CustomDrude", + "CustomFieldSource", + "CustomGrid", + "CustomGridBoundaries", + "CustomHeatPerturbation", + "CustomLorentz", "CustomMedium", "CustomPoleResidue", "CustomSellmeier", - "FullyAnisotropicMedium", - "CustomLorentz", - "CustomDrude", - "CustomDebye", - "CustomAnisotropicMedium", - "LossyMetalMedium", - "SurfaceImpedanceFitterParam", - "HammerstadSurfaceRoughness", - "HuraySurfaceRoughness", - "RotationAroundAxis", - "PerturbationMedium", - "PerturbationPoleResidue", - "NedeljkovicSorefMashanovich", - "ParameterPerturbation", - "LinearHeatPerturbation", - "CustomHeatPerturbation", - "LinearChargePerturbation", - "CustomChargePerturbation", - "PermittivityPerturbation", - "IndexPerturbation", - "NonlinearSpec", - "NonlinearModel", - "NonlinearSusceptibility", - "TwoPhotonAbsorption", - "KerrNonlinearity", - "Structure", - "MeshOverrideStructure", - "ModeSpec", - "ApodizationSpec", - "GaussianPulse", - "ContinuousWave", "CustomSourceTime", - "UniformCurrentSource", - "PlaneWave", - "ModeSource", - "PointDipole", - "GaussianBeam", - "AstigmaticGaussianBeam", - "CustomFieldSource", - "TFSF", - "CustomCurrentSource", - "GaussianBeamProfile", - "AstigmaticGaussianBeamProfile", - "PlaneWaveBeamProfile", + "Cylinder", + "DCCurrentSource", + "DCVoltageSource", + "Debye", + "DefaultAbsorberParameters", + "DefaultPMLParameters", + "DefaultStablePMLParameters", + "DeviceCharacteristics", + "DiffractionData", + "DiffractionDataArray", + "DiffractionMonitor", + "DirectivityData", + "DirectivityMonitor", + "DistanceUnstructuredGrid", + "Drude", + "EMECoefficientData", + "EMECoefficientDataArray", + "EMECoefficientDataset", + "EMECoefficientMonitor", + "EMECompositeGrid", + "EMEExplicitGrid", + "EMEFieldData", + "EMEFieldDataset", + "EMEFieldMonitor", + "EMEFreqSweep", + "EMEGrid", + "EMELengthSweep", + "EMEModeIndexDataArray", + "EMEModeSolverData", + "EMEModeSolverDataset", + "EMEModeSolverMonitor", + "EMEModeSpec", + "EMEModeSweep", + "EMEMonitor", + "EMEPeriodicitySweep", + "EMESMatrixDataArray", + "EMESMatrixDataset", + "EMEScalarFieldDataArray", + "EMEScalarModeFieldDataArray", + "EMESimulation", + "EMESimulationData", + "EMESweepSpec", + "EMEUniformGrid", + "FieldData", + "FieldDataset", + "FieldGrid", "FieldMonitor", - "FieldTimeMonitor", - "AuxFieldTimeMonitor", - "FluxMonitor", - "FluxTimeMonitor", - "ModeMonitor", - "ModeSolverMonitor", - "PermittivityMonitor", + "FieldProjectionAngleData", + "FieldProjectionAngleDataArray", "FieldProjectionAngleMonitor", + "FieldProjectionCartesianData", + "FieldProjectionCartesianDataArray", "FieldProjectionCartesianMonitor", + "FieldProjectionKSpaceData", + "FieldProjectionKSpaceDataArray", "FieldProjectionKSpaceMonitor", "FieldProjectionSurface", - "DiffractionMonitor", - "DirectivityMonitor", - "RunTimeSpec", - "Simulation", "FieldProjector", - "ScalarFieldDataArray", - "ScalarModeFieldDataArray", - "ScalarModeFieldCylindricalDataArray", - "ScalarFieldTimeDataArray", - "SpatialDataArray", - "SpatialVoltageDataArray", - "ModeAmpsDataArray", - "ModeIndexDataArray", - "FluxDataArray", - "FluxTimeDataArray", - "FieldProjectionAngleDataArray", - "FieldProjectionCartesianDataArray", - "FieldProjectionKSpaceDataArray", - "DiffractionDataArray", - "HeatDataArray", - "ChargeDataArray", - "FieldDataset", - "FieldTimeDataset", - "PermittivityDataset", - "ModeSolverDataset", - "FieldData", "FieldTimeData", - "AuxFieldTimeData", - "PermittivityData", + "FieldTimeDataset", + "FieldTimeMonitor", + "FixedAngleSpec", + "FixedInPlaneKSpec", + "FluidMedium", + "FluidSpec", "FluxData", + "FluxDataArray", + "FluxMonitor", "FluxTimeData", - "ModeData", - "ModeSolverData", - "AbstractFieldProjectionData", - "FieldProjectionAngleData", - "FieldProjectionCartesianData", - "FieldProjectionKSpaceData", - "DiffractionData", - "DirectivityData", - "SimulationData", - "DATA_TYPE_MAP", - "BoundarySpec", - "Boundary", - "BoundaryEdge", - "BoundaryEdgeType", - "BlochBoundary", - "Periodic", - "PECBoundary", - "PMCBoundary", - "PML", - "StablePML", - "Absorber", - "PMLParams", - "AbsorberParams", - "PMLTypes", - "DefaultPMLParameters", - "DefaultStablePMLParameters", - "DefaultAbsorberParameters", - "C_0", - "ETA_0", - "HBAR", - "EPSILON_0", - "MU_0", - "Q_e", - "K_B", - "inf", - "frequencies", - "wavelengths", - "material_library", - "Graphene", - "AbstractMedium", + "FluxTimeDataArray", + "FluxTimeMonitor", + "FossumCarrierLifetime", + "FreqRange", + "FullyAnisotropicMedium", + "GaussianBeam", + "GaussianBeamProfile", + "GaussianDoping", + "GaussianPulse", "Geometry", - "Source", - "SourceTime", - "Monitor", - "YeeGrid", - "FieldGrid", - "Coords1D", - "log", - "set_logging_file", - "set_logging_console", - "config", - "__version__", - "Updater", - "AdmittanceNetwork", - "CoaxialLumpedResistor", + "GeometryGroup", + "Graphene", + "Grid", + "GridRefinement", + "GridRefinementLine", + "GridRefinementRegion", + "GridSpec", + "HammerstadSurfaceRoughness", + "HeatBoundarySpec", + "HeatChargeBoundarySpec", + "HeatChargeSimulation", + "HeatChargeSimulationData", + "HeatDataArray", + "HeatFluxBC", + "HeatFromElectricSource", + "HeatSimulation", + "HeatSimulationData", + "HeatSource", + "HeuristicPECStaircasing", + "HuraySurfaceRoughness", + "IndexPerturbation", + "IndexedDataArray", + "IndexedFieldVoltageDataArray", + "IndexedTimeDataArray", + "IndexedVoltageDataArray", + "InsulatingBC", + "IsothermalSteadyChargeDCAnalysis", + "KerrNonlinearity", + "LayerRefinementSpec", + "LinearChargePerturbation", + "LinearHeatPerturbation", "LinearLumpedElement", + "Lorentz", + "LossyMetalMedium", "LumpedElement", "LumpedResistor", - "RectangularLumpedElement", + "Medium", + "Medium2D", + "MediumMediumInterface", + "MeshOverrideStructure", + "ModeAmpsDataArray", + "ModeData", + "ModeIndexDataArray", + "ModeMonitor", + "ModeSimulation", + "ModeSimulationData", + "ModeSolverData", + "ModeSolverDataset", + "ModeSolverMonitor", + "ModeSource", + "ModeSpec", + "ModulationSpec", + "Monitor", + "MultiPhysicsMedium", + "NedeljkovicSorefMashanovich", + "NonlinearModel", + "NonlinearSpec", + "NonlinearSusceptibility", + "PECBoundary", + "PECConformal", + "PECMedium", + "PMCBoundary", + "PMCMedium", + "PMLParams", + "PMLTypes", + "ParameterPerturbation", + "Periodic", + "PermittivityData", + "PermittivityDataset", + "PermittivityMonitor", + "PermittivityPerturbation", + "PerturbationMedium", + "PerturbationPoleResidue", + "PlaneWave", + "PlaneWaveBeamProfile", + "PointDataArray", + "PointDipole", + "PolarizedAveraging", + "PoleResidue", + "PolySlab", + "Q_e", + "QuasiUniformGrid", "RLCNetwork", + "RadiativeRecombination", + "RectangularLumpedElement", + "RotationAroundAxis", + "RunTimeSpec", + "ScalarFieldDataArray", + "ScalarFieldTimeDataArray", + "ScalarModeFieldCylindricalDataArray", + "ScalarModeFieldDataArray", "Scene", - "StructureStructureInterface", - "StructureBoundary", - "MediumMediumInterface", - "StructureSimulationBoundary", + "Sellmeier", + "SemiconductorMedium", + "ShockleyReedHallRecombination", + "Simulation", "SimulationBoundary", - "FluidMedium", - "FluidSpec", + "SimulationData", + "SlotboomBandGapNarrowing", "SolidMedium", "SolidSpec", - "ChargeConductorMedium", - "SemiconductorMedium", - "ChargeInsulatorMedium", - "HeatSimulation", - "HeatSimulationData", - "HeatChargeSimulationData", - "DeviceCharacteristics", - "TemperatureBC", - "ConvectionBC", - "HeatFluxBC", - "HeatBoundarySpec", - "VoltageBC", - "CurrentBC", - "InsulatingBC", - "UniformHeatSource", - "HeatSource", - "HeatFromElectricSource", - "UniformUnstructuredGrid", - "DistanceUnstructuredGrid", - "GridRefinementRegion", - "GridRefinementLine", - "TemperatureData", - "TemperatureMonitor", - "HeatChargeSimulation", - "SteadyPotentialData", - "SteadyFreeCarrierData", - "SteadyEnergyBandData", + "Source", + "SourceTime", + "SpaceModulation", + "SpaceTimeModulation", + "SpatialDataArray", + "SpatialVoltageDataArray", + "Sphere", + "StablePML", + "Staircasing", "SteadyCapacitanceData", - "CaugheyThomasMobility", - "ConstantMobilityModel", - "SlotboomBandGapNarrowing", - "ShockleyReedHallRecombination", - "FossumCarrierLifetime", - "AugerRecombination", - "RadiativeRecombination", - "ConstantDoping", - "GaussianDoping", - "HeatChargeBoundarySpec", - "SteadyPotentialMonitor", - "SteadyFreeCarrierMonitor", - "SteadyEnergyBandMonitor", "SteadyCapacitanceMonitor", - "SpaceTimeModulation", - "SpaceModulation", - "ContinuousWaveTimeModulation", - "ModulationSpec", - "PointDataArray", - "CellDataArray", - "IndexedDataArray", - "IndexedVoltageDataArray", + "SteadyElectricFieldData", + "SteadyElectricFieldMonitor", + "SteadyEnergyBandData", + "SteadyEnergyBandMonitor", + "SteadyFreeCarrierData", + "SteadyFreeCarrierMonitor", + "SteadyPotentialData", + "SteadyPotentialMonitor", "SteadyVoltageDataArray", - "TriangularGridDataset", - "TetrahedralGridDataset", - "medium_from_nk", + "Structure", + "StructureBoundary", + "StructureSimulationBoundary", + "StructureStructureInterface", "SubpixelSpec", - "Staircasing", - "VolumetricAveraging", - "PolarizedAveraging", - "ContourPathAveraging", - "HeuristicPECStaircasing", - "PECConformal", "SurfaceImpedance", + "SurfaceImpedanceFitterParam", + "TemperatureBC", + "TemperatureData", + "TemperatureMonitor", + "TetrahedralGridDataset", + "Transformed", + "TriangleMesh", + "TriangularGridDataset", + "TwoPhotonAbsorption", + "UniformCurrentSource", + "UniformGrid", + "UniformHeatSource", + "UniformUnstructuredGrid", + "UnsteadyHeatAnalysis", + "UnsteadySpec", + "Updater", "VisualizationSpec", - "EMESimulation", - "EMESimulationData", - "EMEMonitor", - "EMEModeSolverMonitor", - "EMEFieldMonitor", - "EMESMatrixDataArray", - "EMEFieldDataset", - "EMECoefficientDataset", - "EMESMatrixDataset", - "EMEModeSolverData", - "EMEFieldData", - "EMECoefficientData", - "EMECoefficientMonitor", - "EMEModeSpec", - "EMEGrid", - "EMEUniformGrid", - "EMECompositeGrid", - "EMEExplicitGrid", - "EMEScalarFieldDataArray", - "EMEScalarModeFieldDataArray", - "EMEModeIndexDataArray", - "EMECoefficientDataArray", - "EMEModeSolverDataset", - "EMESweepSpec", - "EMELengthSweep", - "EMEModeSweep", - "EMEFreqSweep", - "EMEPeriodicitySweep", - "ModeSimulation", - "ModeSimulationData", - "FixedAngleSpec", - "FixedInPlaneKSpec", - "MultiPhysicsMedium", - "DCVoltageSource", - "DCCurrentSource", + "VoltageBC", "VoltageSourceType", - "IsothermalSteadyChargeDCAnalysis", - "ChargeToleranceSpec", - "AntennaMetricsData", + "VolumeMeshData", + "VolumeMeshMonitor", + "VolumeMesher", + "VolumeMesherData", + "VolumetricAveraging", + "YeeGrid", + "__version__", + "config", + "frequencies", + "inf", + "log", + "material_library", + "medium_from_nk", + "restore_matplotlib_rcparams", + "set_logging_console", + "set_logging_file", + "wavelengths", ] diff --git a/tidy3d/__main__.py b/tidy3d/__main__.py index da4f1a994d..6021d3367f 100644 --- a/tidy3d/__main__.py +++ b/tidy3d/__main__.py @@ -1,5 +1,7 @@ """command-line interface. For instructions run `python -m tidy3d --help`""" +from __future__ import annotations + import argparse import sys diff --git a/tidy3d/compat.py b/tidy3d/compat.py index 6060407fe8..2e81d76c26 100644 --- a/tidy3d/compat.py +++ b/tidy3d/compat.py @@ -1,8 +1,21 @@ """Compatibility layer for handling differences between package versions.""" +from __future__ import annotations + +import functools +import importlib + +from packaging.version import parse as parse_version + try: from xarray.structure import alignment except ImportError: from xarray.core import alignment + +@functools.lru_cache(maxsize=8) +def _shapely_is_older_than(version: str) -> bool: + return parse_version(importlib.metadata.version("shapely")) < parse_version(version) + + __all__ = ["alignment"] diff --git a/tidy3d/components/apodization.py b/tidy3d/components/apodization.py index 9dd8614094..6b7567fd64 100644 --- a/tidy3d/components/apodization.py +++ b/tidy3d/components/apodization.py @@ -1,10 +1,13 @@ """Defines specification for apodization.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pd -from ..constants import SECOND -from ..exceptions import SetupError +from tidy3d.constants import SECOND +from tidy3d.exceptions import SetupError + from .base import Tidy3dBaseModel, skip_if_fields_missing from .types import ArrayFloat1D, Ax from .viz import add_ax_if_none diff --git a/tidy3d/components/autograd/__init__.py b/tidy3d/components/autograd/__init__.py index e80b43fd42..a2e9eea893 100644 --- a/tidy3d/components/autograd/__init__.py +++ b/tidy3d/components/autograd/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .boxes import TidyArrayBox from .functions import interpn from .types import ( @@ -12,18 +14,18 @@ from .utils import get_static, is_tidy_box, split_list __all__ = [ + "AutogradFieldMap", + "AutogradTraced", "TidyArrayBox", + "TracedCoordinate", "TracedFloat", - "TracedSize1D", "TracedSize", - "TracedCoordinate", + "TracedSize1D", "TracedVertices", - "AutogradTraced", - "AutogradFieldMap", + "add_at", "get_static", "interpn", - "split_list", "is_tidy_box", + "split_list", "trapz", - "add_at", ] diff --git a/tidy3d/components/autograd/boxes.py b/tidy3d/components/autograd/boxes.py index 437005d9d5..78aa52289a 100644 --- a/tidy3d/components/autograd/boxes.py +++ b/tidy3d/components/autograd/boxes.py @@ -1,8 +1,9 @@ # Adds some functionality to the autograd arraybox and related autograd patches # NOTE: we do not subclass ArrayBox since that would break autograd's internal checks +from __future__ import annotations import importlib -from typing import Any, Callable, Dict, List, Tuple +from typing import Any, Callable import autograd.numpy as anp from autograd.extend import VJPNode, defjvp, register_notrace @@ -33,9 +34,9 @@ def from_arraybox(cls, box: ArrayBox) -> TidyArrayBox: def __array_function__( self: Any, func: Callable, - types: List[Any], - args: Tuple[Any, ...], - kwargs: Dict[str, Any], + types: list[Any], + args: tuple[Any, ...], + kwargs: dict[str, Any], ) -> Any: """ Handle the dispatch of NumPy functions to autograd's numpy implementation. @@ -102,7 +103,7 @@ def __array_ufunc__( ufunc: Callable, method: str, *inputs: Any, - **kwargs: Dict[str, Any], + **kwargs: dict[str, Any], ) -> Any: """ Handle the dispatch of NumPy ufuncs to autograd's numpy implementation. diff --git a/tidy3d/components/autograd/constants.py b/tidy3d/components/autograd/constants.py new file mode 100644 index 0000000000..99d0d64fb2 --- /dev/null +++ b/tidy3d/components/autograd/constants.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +import numpy as np + +# default number of points per wvl in material for discretizing cylinder in autograd derivative +PTS_PER_WVL_MAT_CYLINDER_DISCRETIZE = 10 + +MAX_NUM_TRACED_STRUCTURES = 500 +MAX_NUM_ADJOINT_PER_FWD = 10 + +GRADIENT_PRECISION = "single" # Options: "single", "double" +GRADIENT_DTYPE_FLOAT = np.float32 if GRADIENT_PRECISION == "single" else np.float64 +GRADIENT_DTYPE_COMPLEX = np.complex64 if GRADIENT_PRECISION == "single" else np.complex128 + +GAUSS_QUADRATURE_ORDER = 7 +QUAD_SAMPLE_FRACTION = 0.4 + +AUTOGRAD_MONITOR_INTERVAL_SPACE_POLY = (1, 1, 1) +AUTOGRAD_MONITOR_INTERVAL_SPACE_CUSTOM = (1, 1, 1) + +DEFAULT_WAVELENGTH_FRACTION = 0.1 +MINIMUM_SPACING = 1e-2 + +EDGE_CLIP_TOLERANCE = 1e-9 diff --git a/tidy3d/components/autograd/derivative_utils.py b/tidy3d/components/autograd/derivative_utils.py index e13b2abcf0..ac6078b877 100644 --- a/tidy3d/components/autograd/derivative_utils.py +++ b/tidy3d/components/autograd/derivative_utils.py @@ -1,395 +1,479 @@ -# utilities for autograd derivative passing +"""Utilities for autograd derivative computation and field gradient evaluation.""" + from __future__ import annotations +from dataclasses import dataclass, field, replace +from typing import Callable, Optional + import numpy as np -import pydantic.v1 as pd import xarray as xr -from ...constants import LARGE_NUMBER -from ..base import Tidy3dBaseModel -from ..data.data_array import ScalarFieldDataArray, SpatialDataArray -from ..types import ArrayLike, Bound, tidycomplex +from tidy3d.components.data.data_array import ScalarFieldDataArray, SpatialDataArray +from tidy3d.components.types import Bound, tidycomplex +from tidy3d.constants import C_0, LARGE_NUMBER + +from .constants import ( + DEFAULT_WAVELENGTH_FRACTION, + GRADIENT_DTYPE_COMPLEX, + GRADIENT_DTYPE_FLOAT, + MINIMUM_SPACING, +) from .types import PathType from .utils import get_static -# we do this because importing these creates circular imports FieldData = dict[str, ScalarFieldDataArray] PermittivityData = dict[str, ScalarFieldDataArray] -class DerivativeSurfaceMesh(Tidy3dBaseModel): - """Stores information about the surfaces of an object to be used for derivative calculation. - - User guide: this class is used to construct derivatives with respect to surface elements - given some forward and adjoint fields stored in a ``DerivativeInfo`` class. To use it, - you must specify the central locations of all the surface elements in ``centers``, - along with the area of each element in ``areas``. Then you need to specify three orthogonal - vectors (``normals``, ``perps1`` and ``perps2``). The derivative will be computed with - respect to a change in material along the ``normals`` direction. It is important to note - that the sign of these basis vectors is irrelevant since we end up multiplying the forward - and adjoint fields together in these bases. - - The gradient is with respect to a change from the surface element permittivity from the - ``eps_in`` to ``eps_out`` field. So in principle it is always computing gradients with - respect to an infinitesimal outward shift in the normal direction. For example, for - ``PolySlab.vertices``, this means shifting each edge to the background. - For ``PolySlab.slab_bounds``, this means shifting the bound in either + or - direction if it - is index ``[1]`` or ``[0]`` respectively. This renders the sign of the normal vector - irrelevant. +class LazyInterpolator: + """Lazy wrapper for interpolators that creates them on first access.""" - After this ``DerivativeSurfaceMesh`` is constructed, given some ``DerivativeInfo`` in the - gradient calculation, a call to ``DerivativeInfo.grad_surfaces(x: DerivativeSurfaceMesh)`` - will return the gradient with respect to a change in all of the provided surfaces. + def __init__(self, creator_func: Callable): + """Initialize with a function that creates the interpolator when called.""" + self.creator_func = creator_func + self._interpolator = None - """ + def __call__(self, *args, **kwargs): + """Create interpolator on first call and delegate to it.""" + if self._interpolator is None: + self._interpolator = self.creator_func() + return self._interpolator(*args, **kwargs) - centers: ArrayLike = pd.Field( - ..., - title="Centers", - description="(N, 3) array storing the centers of each surface element.", - ) - - areas: ArrayLike = pd.Field( - ..., - title="Area Elements", - description="(N,) array storing the first perpendicular vectors of each surface element.", - ) - - normals: ArrayLike = pd.Field( - ..., - title="Normals", - description="(N, 3) array storing the normal vectors of each surface element.", - ) - - perps1: ArrayLike = pd.Field( - ..., - title="Perpendiculars 1", - description="(N, 3) array storing the first perpendicular vectors of each surface element.", - ) - - perps2: ArrayLike = pd.Field( - ..., - title="Perpendiculars 1", - description="(N, 3) array storing the first perpendicular vectors of each surface element.", - ) - - -class DerivativeInfo(Tidy3dBaseModel): - """Stores derivative information passed to the ``.compute_derivatives`` methods.""" - - paths: list[PathType] = pd.Field( - ..., - title="Paths to Traced Fields", - description="List of paths to the traced fields that need derivatives calculated.", - ) - - E_der_map: FieldData = pd.Field( - ..., - title="Electric Field Gradient Map", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` store the ' - "multiplication of the forward and adjoint electric fields. The tangential components " - "of this dataset is used when computing adjoint gradients for shifting boundaries. " - "All components are used when computing volume-based gradients.", - ) - - D_der_map: FieldData = pd.Field( - ..., - title="Displacement Field Gradient Map", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` store the ' - "multiplication of the forward and adjoint displacement fields. The normal component " - "of this dataset is used when computing adjoint gradients for shifting boundaries.", - ) - - E_fwd: FieldData = pd.Field( - ..., - title="Forward Electric Fields", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the ' - "forward electric fields used for computing gradients for a given structure.", - ) - - E_adj: FieldData = pd.Field( - ..., - title="Adjoint Electric Fields", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the ' - "adjoint electric fields used for computing gradients for a given structure.", - ) - - D_fwd: FieldData = pd.Field( - ..., - title="Forward Displacement Fields", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the ' - "forward displacement fields used for computing gradients for a given structure.", - ) - - D_adj: FieldData = pd.Field( - ..., - title="Adjoint Displacement Fields", - description='Dataset where the field components ``("Ex", "Ey", "Ez")`` represent the ' - "adjoint displacement fields used for computing gradients for a given structure.", - ) - - eps_data: PermittivityData = pd.Field( - ..., - title="Permittivity Dataset", - description="Dataset of relative permittivity values along all three dimensions. " - "Used for automatically computing permittivity inside or outside of a simple geometry.", - ) - - eps_in: tidycomplex = pd.Field( - title="Permittivity Inside", - description="Permittivity inside of the ``Structure``. " - "Typically computed from ``Structure.medium.eps_model``." - "Used when it can not be computed from ``eps_data`` or when ``eps_approx==True``.", - ) - - eps_out: tidycomplex = pd.Field( - ..., - title="Permittivity Outside", - description="Permittivity outside of the ``Structure``. " - "Typically computed from ``Simulation.medium.eps_model``." - "Used when it can not be computed from ``eps_data`` or when ``eps_approx==True``.", - ) - - eps_background: tidycomplex = pd.Field( - None, - title="Permittivity in Background", - description="Permittivity outside of the ``Structure`` as manually specified by. " - "``Structure.background_medium``. ", - ) - - bounds: Bound = pd.Field( - ..., - title="Geometry Bounds", - description="Bounds corresponding to the structure, used in ``Medium`` calculations.", - ) - - bounds_intersect: Bound = pd.Field( - ..., - title="Geometry and Simulation Intersections Bounds", - description="Bounds corresponding to the minimum intersection between the " - "structure and the simulation it is contained in.", - ) - - frequency: float = pd.Field( - ..., - title="Frequency of adjoint simulation", - description="Frequency at which the adjoint gradient is computed.", - ) - - eps_no_structure: SpatialDataArray = pd.Field( - None, - title="Permittivity Without Structure", - description="The permittivity of the original simulation without the structure that is " - "being differentiated with respect to. Used to approximate permittivity outside of the " - "structure for shape optimization.", - ) - - eps_inf_structure: SpatialDataArray = pd.Field( - None, - title="Permittivity With Infinite Structure", - description="The permittivity of the original simulation where the structure being " - " differentiated with respect to is inifinitely large. Used to approximate permittivity " - "inside of the structure for shape optimization.", - ) - - eps_approx: bool = pd.Field( - False, - title="Use Permittivity Approximation", - description="If ``True``, approximates outside permittivity using ``Simulation.medium``" - "and the inside permittivity using ``Structure.medium``. " - "Only set ``True`` for ``GeometryGroup`` handling where it is difficult to automatically " - "evaluate the inside and outside relative permittivity for each geometry.", - ) - - def updated_paths(self, paths: list[PathType]) -> DerivativeInfo: - """Update this ``DerivativeInfo`` with new set of paths.""" - return self.updated_copy(paths=paths) - - def _eps_in(self, spatial_coords: np.ndarray) -> complex | np.ndarray: - """permittivity inside, used internally.""" - # determine inside medium - if self.eps_inf_structure is not None: - return self.evaluate_eps(spatial_coords, is_inside=True) - return self.eps_in +@dataclass +class DerivativeInfo: + """Stores derivative information passed to the ``._compute_derivatives`` methods. - def _eps_out(self, spatial_coords: np.ndarray) -> complex | np.ndarray: - """permittivity outside, used internally.""" + This dataclass contains all the field data and parameters needed for computing + gradients with respect to geometry perturbations. + """ - # determine background medium - if self.eps_background is not None: - return self.eps_background + # Required fields + paths: list[PathType] + """List of paths to the traced fields that need derivatives calculated.""" + + E_der_map: FieldData + """Electric field gradient map. + Dataset where the field components ("Ex", "Ey", "Ez") store the multiplication + of the forward and adjoint electric fields. The tangential components of this + dataset are used when computing adjoint gradients for shifting boundaries. + All components are used when computing volume-based gradients.""" + + D_der_map: FieldData + """Displacement field gradient map. + Dataset where the field components ("Ex", "Ey", "Ez") store the multiplication + of the forward and adjoint displacement fields. The normal component of this + dataset is used when computing adjoint gradients for shifting boundaries.""" + + E_fwd: FieldData + """Forward electric fields. + Dataset where the field components ("Ex", "Ey", "Ez") represent the forward + electric fields used for computing gradients for a given structure.""" + + E_adj: FieldData + """Adjoint electric fields. + Dataset where the field components ("Ex", "Ey", "Ez") represent the adjoint + electric fields used for computing gradients for a given structure.""" + + D_fwd: FieldData + """Forward displacement fields. + Dataset where the field components ("Ex", "Ey", "Ez") represent the forward + displacement fields used for computing gradients for a given structure.""" + + D_adj: FieldData + """Adjoint displacement fields. + Dataset where the field components ("Ex", "Ey", "Ez") represent the adjoint + displacement fields used for computing gradients for a given structure.""" + + eps_data: PermittivityData + """Permittivity dataset. + Dataset of relative permittivity values along all three dimensions. + Used for automatically computing permittivity inside or outside of a simple geometry.""" + + eps_in: tidycomplex + """Permittivity inside the Structure. + Typically computed from Structure.medium.eps_model. + Used when it cannot be computed from eps_data or when eps_approx=True.""" + + eps_out: tidycomplex + """Permittivity outside the Structure. + Typically computed from Simulation.medium.eps_model. + Used when it cannot be computed from eps_data or when eps_approx=True.""" + + bounds: Bound + """Geometry bounds. + Bounds corresponding to the structure, used in Medium calculations.""" + + bounds_intersect: Bound + """Geometry and simulation intersection bounds. + Bounds corresponding to the minimum intersection between the structure + and the simulation it is contained in.""" + + frequency: float + """Frequency of adjoint simulation at which the gradient is computed.""" + + # Optional fields with defaults + eps_background: Optional[tidycomplex] = None + """Permittivity in background. + Permittivity outside of the Structure as manually specified by + Structure.background_medium.""" + + eps_no_structure: Optional[SpatialDataArray] = None + """Permittivity without structure. + The permittivity of the original simulation without the structure that is + being differentiated with respect to. Used to approximate permittivity + outside of the structure for shape optimization.""" + + eps_inf_structure: Optional[SpatialDataArray] = None + """Permittivity with infinite structure. + The permittivity of the original simulation where the structure being + differentiated with respect to is infinitely large. Used to approximate + permittivity inside of the structure for shape optimization.""" + + eps_approx: bool = False + """Use permittivity approximation. + If True, approximates outside permittivity using Simulation.medium and + the inside permittivity using Structure.medium. Only set True for + GeometryGroup handling where it is difficult to automatically evaluate + the inside and outside relative permittivity for each geometry.""" + + interpolators: Optional[dict] = None + """Pre-computed interpolators. + Optional pre-computed interpolators for field components and permittivity data. + When provided, avoids redundant interpolator creation for multiple geometries + sharing the same field data. This significantly improves performance for + GeometryGroup processing.""" + + # private cache for interpolators + _interpolators_cache: dict = field(default_factory=dict, init=False, repr=False) + + def updated_copy(self, **kwargs): + """Create a copy with updated fields.""" + kwargs.pop("deep", None) + kwargs.pop("validate", None) + return replace(self, **kwargs) - if self.eps_no_structure is not None: - return self.evaluate_eps(spatial_coords, is_inside=False) - - return self.eps_out - - def delta_eps(self, spatial_coords: np.ndarray) -> complex | np.ndarray: - """Change in the permittivity across interface (for E field grads).""" - return self._eps_in(spatial_coords) - self._eps_out(spatial_coords) - - def delta_eps_inv(self, spatial_coords: np.ndarray) -> complex | np.ndarray: - """Change in 1 / permittivity across interface (for D field grads).""" - return 1.0 / self._eps_in(spatial_coords) - 1.0 / self._eps_out(spatial_coords) - - def grad_surfaces(self, surface_mesh: DerivativeSurfaceMesh) -> dict: - """Derivative with respect to the surface mesh elements, given the derivative fields.""" - - # strip out relevant info from `surface_mesh` - spatial_coords = surface_mesh.centers - normals = surface_mesh.normals - perps1 = surface_mesh.perps1 - perps2 = surface_mesh.perps2 - - # unpack electric and displacement fields - E_fwd = self.E_fwd - E_adj = self.E_adj - D_fwd = self.D_fwd - D_adj = self.D_adj - - # compute the E and D fields at the edge centers - E_fwd_at_coords = self.evaluate_flds_at( - fld_dataset=E_fwd, spatial_coords=spatial_coords, freq=self.frequency - ) - E_adj_at_coords = self.evaluate_flds_at( - fld_dataset=E_adj, spatial_coords=spatial_coords, freq=self.frequency - ) - D_fwd_at_coords = self.evaluate_flds_at( - fld_dataset=D_fwd, spatial_coords=spatial_coords, freq=self.frequency - ) - D_adj_at_coords = self.evaluate_flds_at( - fld_dataset=D_adj, spatial_coords=spatial_coords, freq=self.frequency - ) - - # project the relevant field quantities into their respective basis for gradient calculation - D_fwd_norm = self.project_in_basis(D_fwd_at_coords, basis_vector=normals) - D_adj_norm = self.project_in_basis(D_adj_at_coords, basis_vector=normals) - - E_fwd_perp1 = self.project_in_basis(E_fwd_at_coords, basis_vector=perps1) - E_adj_perp1 = self.project_in_basis(E_adj_at_coords, basis_vector=perps1) - - E_fwd_perp2 = self.project_in_basis(E_fwd_at_coords, basis_vector=perps2) - E_adj_perp2 = self.project_in_basis(E_adj_at_coords, basis_vector=perps2) - - # multiply forward and adjoint - D_der_norm = D_fwd_norm * D_adj_norm - E_der_perp1 = E_fwd_perp1 * E_adj_perp1 - E_der_perp2 = E_fwd_perp2 * E_adj_perp2 + @staticmethod + def _get_freq_index(arr: ScalarFieldDataArray, freq: float) -> int: + """Get the index of the frequency in the array's frequency coordinates.""" + if "f" not in arr.dims: + return None + freq_coords = arr.coords["f"].data + idx = np.argmin(np.abs(freq_coords - freq)) + return int(idx) - # approximate permittivity in and out - delta_eps_inv = self.delta_eps_inv(spatial_coords=spatial_coords) - delta_eps = self.delta_eps(spatial_coords=spatial_coords) + @staticmethod + def _nan_to_num_if_needed(coords: np.ndarray) -> np.ndarray: + """Convert NaN and infinite values to finite numbers, optimized for finite inputs.""" + # skip check for small arrays - overhead exceeds benefit + if coords.size < 1000: + return np.nan_to_num(coords, posinf=LARGE_NUMBER, neginf=-LARGE_NUMBER) - # put together VJP using D_normal and E_perp integration - vjps = 0.0 + if np.isfinite(coords).all(): + return coords + return np.nan_to_num(coords, posinf=LARGE_NUMBER, neginf=-LARGE_NUMBER) - # perform D-normal integral - contrib_D = -delta_eps_inv * D_der_norm - vjps += contrib_D + @staticmethod + def _evaluate_with_interpolators( + interpolators: dict, coords: np.ndarray + ) -> dict[str, np.ndarray]: + """Evaluate field components at coordinates using cached interpolators. + + Parameters + ---------- + interpolators : dict + Dictionary mapping field component names to ``RegularGridInterpolator`` objects. + coords : np.ndarray + Spatial coordinates (N, 3) where fields are evaluated. + + Returns + ------- + dict[str, np.ndarray] + Dictionary mapping component names to field values at coordinates. + """ + coords = DerivativeInfo._nan_to_num_if_needed(coords) + if coords.dtype != GRADIENT_DTYPE_FLOAT and coords.dtype != GRADIENT_DTYPE_COMPLEX: + coords = coords.astype(GRADIENT_DTYPE_FLOAT, copy=False) + return {name: interp(coords) for name, interp in interpolators.items()} + + def create_interpolators(self, dtype=GRADIENT_DTYPE_FLOAT) -> dict: + """Create interpolators for field components and permittivity data. + + Creates and caches ``RegularGridInterpolator`` objects for all field components + (E_fwd, E_adj, D_fwd, D_adj) and permittivity data (eps_inf, eps_no). + This caching strategy significantly improves performance by avoiding + repeated interpolator construction in gradient evaluation loops. + + Parameters + ---------- + dtype : np.dtype = GRADIENT_DTYPE_FLOAT + Data type for interpolation coordinates and values. + + Returns + ------- + dict + Nested dictionary structure: + - Field data: {"E_fwd": {"Ex": interpolator, ...}, ...} + - Permittivity: {"eps_inf": interpolator, "eps_no": interpolator} + """ + from scipy.interpolate import RegularGridInterpolator - # perform E-perpendicular integrals - for E_der in (E_der_perp1, E_der_perp2): - contrib_E = E_der * delta_eps - vjps += contrib_E + cache_key = str(dtype) + if cache_key in self._interpolators_cache: + return self._interpolators_cache[cache_key] + + interpolators = {} + coord_cache = {} + + def _make_lazy_interpolator_group(field_data_dict, group_key, is_field_group=True): + """Helper to create a group of lazy interpolators.""" + if is_field_group: + interpolators[group_key] = {} + + for component_name, arr in field_data_dict.items(): + # use object ID for caching to handle shared grids + arr_id = id(arr.data) + if arr_id not in coord_cache: + points = tuple(c.data.astype(dtype, copy=False) for c in (arr.x, arr.y, arr.z)) + coord_cache[arr_id] = points + points = coord_cache[arr_id] + + # defer data selection until the interpolator is called + def creator_func(arr=arr, points=points): + freq_idx = self._get_freq_index(arr, self.frequency) + data = arr.data if freq_idx is None else arr.isel(f=freq_idx).data + data = data.astype( + GRADIENT_DTYPE_COMPLEX if np.iscomplexobj(data) else dtype, copy=False + ) + return RegularGridInterpolator( + points, data, method="linear", bounds_error=False, fill_value=None + ) + + if is_field_group: + interpolators[group_key][component_name] = LazyInterpolator(creator_func) + else: + # for permittivity, store directly with the key (not nested) + interpolators[component_name] = LazyInterpolator(creator_func) + + # process field interpolators (nested dictionaries) + for group_key, data_dict in [ + ("E_fwd", self.E_fwd), + ("E_adj", self.E_adj), + ("D_fwd", self.D_fwd), + ("D_adj", self.D_adj), + ]: + _make_lazy_interpolator_group(data_dict, group_key, is_field_group=True) + + # process permittivity interpolators + if self.eps_inf_structure is not None: + _make_lazy_interpolator_group( + {"eps_inf": self.eps_inf_structure}, None, is_field_group=False + ) + if self.eps_no_structure is not None: + _make_lazy_interpolator_group( + {"eps_no": self.eps_no_structure}, None, is_field_group=False + ) - return surface_mesh.areas * vjps + self._interpolators_cache[cache_key] = interpolators + return interpolators - def evaluate_eps( + def evaluate_gradient_at_points( self, - spatial_coords: np.ndarray, # (N, 3) - is_inside: bool, - ) -> SpatialDataArray: - """Evaluate permittivity without the structure at a set of points.""" - - permittivity_array = self.eps_inf_structure if is_inside else self.eps_no_structure - - if permittivity_array is None: - raise ValueError("Can't evaluate eps because the permittivity array is missing.") - - key = "key" - eps_out = self.evaluate_flds_at( - fld_dataset={key: permittivity_array}, - spatial_coords=spatial_coords, - freq=self.frequency, - )[key] - return eps_out.values - - @staticmethod - def evaluate_flds_at( - fld_dataset: dict[str, ScalarFieldDataArray], - spatial_coords: np.ndarray, # (N, 3) - freq: float, - ) -> dict[str, ScalarFieldDataArray]: - """Compute the value of an dict with keys Ex, Ey, Ez at a set of spatial locations.""" - - from scipy.interpolate import RegularGridInterpolator + spatial_coords: np.ndarray, + normals: np.ndarray, + perps1: np.ndarray, + perps2: np.ndarray, + interpolators: Optional[dict] = None, + ) -> np.ndarray: + """Compute adjoint gradients at surface points for shape optimization. + + Implements the surface integral formulation for computing gradients with respect + to geometry perturbations. + + Parameters + ---------- + spatial_coords : np.ndarray + (N, 3) array of surface evaluation points. + normals : np.ndarray + (N, 3) array of outward-pointing normal vectors at each surface point. + perps1 : np.ndarray + (N, 3) array of first tangent vectors perpendicular to normals. + perps2 : np.ndarray + (N, 3) array of second tangent vectors perpendicular to both normals and perps1. + interpolators : dict = None + Pre-computed field interpolators for efficiency. + + Returns + ------- + np.ndarray + (N,) array of gradient values at each surface point. Must be integrated + with appropriate quadrature weights to get total gradient. + """ + if interpolators is None: + raise NotImplementedError( + "Direct field evaluation without interpolators is not implemented. " + "Please create interpolators using 'create_interpolators()' first." + ) - coords = np.nan_to_num(spatial_coords, posinf=LARGE_NUMBER, neginf=-LARGE_NUMBER) - components = {} + # evaluate all field components at surface points + E_fwd_at_coords = { + name: interp(spatial_coords) for name, interp in interpolators["E_fwd"].items() + } + E_adj_at_coords = { + name: interp(spatial_coords) for name, interp in interpolators["E_adj"].items() + } + D_fwd_at_coords = { + name: interp(spatial_coords) for name, interp in interpolators["D_fwd"].items() + } + D_adj_at_coords = { + name: interp(spatial_coords) for name, interp in interpolators["D_adj"].items() + } + + # project fields onto local surface basis (normal + two tangents) + D_fwd_norm = self._project_in_basis(D_fwd_at_coords, basis_vector=normals) + D_adj_norm = self._project_in_basis(D_adj_at_coords, basis_vector=normals) + + E_fwd_perp1 = self._project_in_basis(E_fwd_at_coords, basis_vector=perps1) + E_adj_perp1 = self._project_in_basis(E_adj_at_coords, basis_vector=perps1) + + E_fwd_perp2 = self._project_in_basis(E_fwd_at_coords, basis_vector=perps2) + E_adj_perp2 = self._project_in_basis(E_adj_at_coords, basis_vector=perps2) + + # compute field products + D_der_norm = D_fwd_norm * D_adj_norm + E_der_perp1 = E_fwd_perp1 * E_adj_perp1 + E_der_perp2 = E_fwd_perp2 * E_adj_perp2 - edge_index_dim = "edge_index" - n_points = coords.shape[0] + # get permittivity jumps across interface + if "eps_inf" in interpolators: + eps_in = interpolators["eps_inf"](spatial_coords) + else: + eps_in = self.eps_in - for fld_name, arr in fld_dataset.items(): - data = arr.sel(f=freq).values if "f" in arr.dims else arr.values - points = tuple(arr.coords[dim].values for dim in "xyz") + if "eps_no" in interpolators: + eps_out = interpolators["eps_no"](spatial_coords) + elif self.eps_background is not None: + eps_out = self.eps_background + else: + eps_out = self.eps_out - interpolator = RegularGridInterpolator( - points, data, method="linear", bounds_error=False, fill_value=None - ) - result = interpolator(coords) + delta_eps_inv = 1.0 / eps_in - 1.0 / eps_out + delta_eps = eps_in - eps_out - components[fld_name] = xr.DataArray( - result, - coords={edge_index_dim: np.arange(n_points)}, - dims=[edge_index_dim], - name=fld_name, - ) + vjps = -delta_eps_inv * D_der_norm + E_der_perp1 * delta_eps + E_der_perp2 * delta_eps - return components + return vjps @staticmethod - def project_in_basis( - der_dataset: xr.Dataset, + def _project_in_basis( + field_components: dict[str, np.ndarray], basis_vector: np.ndarray, - ) -> xr.DataArray: - """Project a derivative dataset along a supplied basis vector.""" - value = 0.0 - for coeffs, dim in zip(basis_vector.T, "xyz"): - value += coeffs * der_dataset[f"E{dim}"] - return value + ) -> np.ndarray: + """Project 3D field components onto a basis vector. + + Parameters + ---------- + field_components : dict[str, np.ndarray] + Dictionary with keys like "Ex", "Ey", "Ez" or "Dx", "Dy", "Dz" containing field values. + basis_vector : np.ndarray + (N, 3) array of basis vectors, one per evaluation point. + + Returns + ------- + np.ndarray + (N,) array of projected field values. + """ + prefix = next(iter(field_components.keys()))[0] + field_matrix = np.stack([field_components[f"{prefix}{dim}"] for dim in "xyz"], axis=1) + return np.einsum("ij,ij->i", field_matrix, basis_vector) + + def adaptive_vjp_spacing( + self, + wl_fraction: float = DEFAULT_WAVELENGTH_FRACTION, + min_allowed_spacing: float = MINIMUM_SPACING, + ) -> float: + """Compute adaptive spacing for finite-difference gradient evaluation. + + Determines an appropriate spatial resolution based on the material + properties and electromagnetic wavelength/skin depth. + + Parameters + ---------- + wl_fraction : float = 0.1 + Fraction of wavelength/skin depth to use as spacing. + min_allowed_spacing : float = 1e-2 + Minimum allowed spacing to prevent numerical issues. + + Returns + ------- + float + Adaptive spacing value for gradient evaluation. + """ + eps_real = np.asarray(self.eps_in, dtype=np.complex128).real + + dx_candidates = [] + + # wavelength-based sampling for dielectric materials + if np.any(eps_real > 0): + eps_max = eps_real[eps_real > 0].max() + lambda_min = C_0 / (self.frequency * np.sqrt(eps_max)) + dx_candidates.append(wl_fraction * lambda_min) + + # skin depth-based sampling for metallic materials + if np.any(eps_real <= 0): + omega = 2 * np.pi * self.frequency + eps_neg = eps_real[eps_real <= 0] + delta_min = C_0 / (omega * np.sqrt(np.abs(eps_neg).max())) + dx_candidates.append(wl_fraction * delta_min) + + return max(min(dx_candidates), min_allowed_spacing) -# TODO: could we move this into a DataArray method? def integrate_within_bounds(arr: xr.DataArray, dims: list[str], bounds: Bound) -> xr.DataArray: - """integrate a data array within bounds, assumes bounds are [2, N] for N dims.""" - - # order bounds with dimension first (N, 2) + """Integrate a data array within specified spatial bounds. + + Clips the integration domain to the specified bounds and performs + numerical integration using the trapezoidal rule. + + Parameters + ---------- + arr : xr.DataArray + Data array to integrate. + dims : list[str] + Dimensions to integrate over (e.g., ['x', 'y', 'z']). + bounds : Bound + Integration bounds as [[xmin, ymin, zmin], [xmax, ymax, zmax]]. + + Returns + ------- + xr.DataArray + Result of integration with specified dimensions removed. + + Notes + ----- + - Coordinates outside bounds are clipped, effectively setting dL=0 + - Only integrates dimensions with more than one coordinate point + - Uses xarray's integrate method (trapezoidal rule) + """ bounds = np.asarray(bounds).T all_coords = {} - # loop over all dimensions for dim, (bmin, bmax) in zip(dims, bounds): bmin = get_static(bmin) bmax = get_static(bmax) - coord_values = np.copy(arr.coords[dim].data) - - # reset all coordinates outside of bounds to the bounds, so that dL = 0 in integral - np.clip(coord_values, bmin, bmax, out=coord_values) - - all_coords[dim] = coord_values + # clip coordinates to bounds (sets dL=0 outside bounds) + coord_values = arr.coords[dim].data + all_coords[dim] = np.clip(coord_values, bmin, bmax) _arr = arr.assign_coords(**all_coords) - # uses trapezoidal rule - # https://docs.xarray.dev/en/stable/generated/xarray.DataArray.integrate.html + # only integrate dimensions with multiple points dims_integrate = [dim for dim in dims if len(_arr.coords[dim]) > 1] return _arr.integrate(coord=dims_integrate) __all__ = [ - "integrate_within_bounds", "DerivativeInfo", + "integrate_within_bounds", ] diff --git a/tidy3d/components/autograd/functions.py b/tidy3d/components/autograd/functions.py index 762740a32c..96d10f1547 100644 --- a/tidy3d/components/autograd/functions.py +++ b/tidy3d/components/autograd/functions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import itertools import autograd.numpy as anp @@ -198,6 +200,34 @@ def trapz(y: NDArray, x: NDArray = None, dx: float = 1.0, axis: int = -1) -> flo @primitive +def _add_at(x: NDArray, indices_x: tuple, y: NDArray) -> NDArray: + """ + Add values to specified indices of an array. + + Autograd requires that arguments to primitives are passed in positionally. + ``add_at`` is the public-facing wrapper for this function, + which allows keyword arguments in case users pass in kwargs. + """ + out = np.copy(x) # Copy to preserve 'x' for gradient computation + out[tuple(indices_x)] += y + return out + + +defvjp( + _add_at, + lambda ans, x, indices_x, y: unbroadcast_f(x, lambda g: g), + lambda ans, x, indices_x, y: lambda g: g[tuple(indices_x)], + argnums=(0, 2), +) + +defjvp( + _add_at, + lambda g, ans, x, indices_x, y: broadcast(g, ans), + lambda g, ans, x, indices_x, y: _add_at(anp.zeros_like(ans), indices_x, g), + argnums=(0, 2), +) + + def add_at(x: NDArray, indices_x: tuple, y: NDArray) -> NDArray: """ Add values to specified indices of an array. @@ -219,28 +249,11 @@ def add_at(x: NDArray, indices_x: tuple, y: NDArray) -> NDArray: np.ndarray The modified array with values added at the specified indices. """ - out = np.copy(x) # Copy to preserve 'x' for gradient computation - out[tuple(indices_x)] += y - return out - - -defvjp( - add_at, - lambda ans, x, indices_x, y: unbroadcast_f(x, lambda g: g), - lambda ans, x, indices_x, y: lambda g: g[tuple(indices_x)], - argnums=(0, 2), -) - -defjvp( - add_at, - lambda g, ans, x, indices_x, y: broadcast(g, ans), - lambda g, ans, x, indices_x, y: add_at(anp.zeros_like(ans), indices_x, g), - argnums=(0, 2), -) + return _add_at(x, indices_x, y) __all__ = [ + "add_at", "interpn", "trapz", - "add_at", ] diff --git a/tidy3d/components/autograd/types.py b/tidy3d/components/autograd/types.py index e8be92bb74..52ac58c8ab 100644 --- a/tidy3d/components/autograd/types.py +++ b/tidy3d/components/autograd/types.py @@ -1,6 +1,7 @@ # type information for autograd # utilities for working with autograd +from __future__ import annotations import copy import typing @@ -10,8 +11,7 @@ from autograd.extend import Box, defvjp, primitive from tidy3d.components.type_util import _add_schema - -from ..types import ArrayFloat2D, ArrayLike, Complex, Size1D +from tidy3d.components.types import ArrayFloat2D, ArrayLike, Complex, Size1D # add schema to the Box _add_schema(Box, title="AutogradBox", field_type_str="autograd.tracer.Box") @@ -36,7 +36,7 @@ # poles TracedComplex = typing.Union[Complex, Box] -TracedPoleAndResidue = typing.Tuple[TracedComplex, TracedComplex] +TracedPoleAndResidue = tuple[TracedComplex, TracedComplex] # The data type that we pass in and out of the web.run() @autograd.primitive AutogradTraced = typing.Union[Box, ArrayLike] @@ -46,11 +46,11 @@ InterpolationType = typing.Literal["nearest", "linear"] __all__ = [ + "AutogradFieldMap", + "AutogradTraced", + "TracedCoordinate", "TracedFloat", - "TracedSize1D", "TracedSize", - "TracedCoordinate", + "TracedSize1D", "TracedVertices", - "AutogradTraced", - "AutogradFieldMap", ] diff --git a/tidy3d/components/autograd/utils.py b/tidy3d/components/autograd/utils.py index 0a1fbfd43d..7f8e795526 100644 --- a/tidy3d/components/autograd/utils.py +++ b/tidy3d/components/autograd/utils.py @@ -1,28 +1,42 @@ # utilities for working with autograd +from __future__ import annotations -import typing +from collections.abc import Iterable +from typing import Any from autograd.tracer import getval -def get_static(x: typing.Any) -> typing.Any: +def get_static(x: Any) -> Any: """Get the 'static' (untraced) version of some value.""" return getval(x) -def split_list(x: list[typing.Any], index: int) -> (list[typing.Any], list[typing.Any]): +def split_list(x: list[Any], index: int) -> (list[Any], list[Any]): """Split a list at a given index.""" x = list(x) return x[:index], x[index:] -def is_tidy_box(x: typing.Any) -> bool: +def is_tidy_box(x: Any) -> bool: """Check if a value is a tidy box.""" return getattr(x, "_tidy", False) +def contains(target: Any, seq: Iterable[Any]) -> bool: + """Return ``True`` if target occurs anywhere within arbitrarily nested iterables.""" + for x in seq: + if x == target: + return True + if isinstance(x, Iterable) and not isinstance(x, (str, bytes)): + if contains(target, x): + return True + return False + + __all__ = [ + "contains", "get_static", - "split_list", "is_tidy_box", + "split_list", ] diff --git a/tidy3d/components/base.py b/tidy3d/components/base.py index 9615c33beb..36eb671a08 100644 --- a/tidy3d/components/base.py +++ b/tidy3d/components/base.py @@ -11,7 +11,7 @@ import tempfile from functools import wraps from math import ceil -from typing import Any, Callable, Dict, List, Tuple, Union +from typing import Any, Callable, Optional, Union import h5py import numpy as np @@ -23,8 +23,9 @@ from autograd.tracer import isbox from pydantic.v1.fields import ModelField -from ..exceptions import FileError -from ..log import log +from tidy3d.exceptions import FileError +from tidy3d.log import log + from .autograd.types import AutogradFieldMap, Box from .autograd.utils import get_static from .data.data_array import DATA_ARRAY_MAP, DataArray @@ -70,7 +71,7 @@ def cached_property(cached_property_getter): def ndarray_encoder(val): """How a ``np.ndarray`` gets handled before saving to json.""" if np.any(np.iscomplex(val)): - return dict(real=val.real.tolist(), imag=val.imag.tolist()) + return {"real": val.real.tolist(), "imag": val.imag.tolist()} return val.real.tolist() @@ -92,7 +93,7 @@ def _get_valid_extension(fname: str) -> str: ) -def skip_if_fields_missing(fields: List[str], root=False): +def skip_if_fields_missing(fields: list[str], root=False): """Decorate ``validator`` to check that other fields have passed validation.""" def actual_decorator(validator): @@ -110,8 +111,7 @@ def _validator(cls, *args, **kwargs): ) if root: return values - else: - return kwargs.get("val") if "val" in kwargs.keys() else args[0] + return kwargs.get("val") if "val" in kwargs else args[0] return validator(cls, *args, **kwargs) @@ -229,7 +229,7 @@ def copy(self, deep: bool = True, validate: bool = True, **kwargs) -> Tidy3dBase return new_copy def updated_copy( - self, path: str = None, deep: bool = True, validate: bool = True, **kwargs + self, path: Optional[str] = None, deep: bool = True, validate: bool = True, **kwargs ) -> Tidy3dBaseModel: """Make copy of a component instance with ``**kwargs`` indicating updated field values. @@ -270,7 +270,7 @@ def updated_copy( f"Could not grab integer index from path '{path}'. " f"Please correct the sub path containing '{integer_index_path}' to be an " f"integer index into '{field_name}' (containing {len(sub_component)} elements)." - ) + ) from None sub_component_list = list(sub_component) sub_component = sub_component_list[index] @@ -307,7 +307,9 @@ def help(self, methods: bool = False) -> None: rich.inspect(self, methods=methods) @classmethod - def from_file(cls, fname: str, group_path: str = None, **parse_obj_kwargs) -> Tidy3dBaseModel: + def from_file( + cls, fname: str, group_path: Optional[str] = None, **parse_obj_kwargs + ) -> Tidy3dBaseModel: """Loads a :class:`Tidy3dBaseModel` from .yaml, .json, .hdf5, or .hdf5.gz file. Parameters @@ -333,7 +335,7 @@ def from_file(cls, fname: str, group_path: str = None, **parse_obj_kwargs) -> Ti return cls.parse_obj(model_dict, **parse_obj_kwargs) @classmethod - def dict_from_file(cls, fname: str, group_path: str = None) -> dict: + def dict_from_file(cls, fname: str, group_path: Optional[str] = None) -> dict: """Loads a dictionary containing the model from a .yaml, .json, .hdf5, or .hdf5.gz file. Parameters @@ -590,7 +592,7 @@ def _json_string_from_hdf5(cls, fname: str) -> str: @classmethod def dict_from_hdf5( - cls, fname: str, group_path: str = "", custom_decoders: List[Callable] = None + cls, fname: str, group_path: str = "", custom_decoders: Optional[list[Callable]] = None ) -> dict: """Loads a dictionary containing the model contents from a .hdf5 file. @@ -668,7 +670,7 @@ def from_hdf5( cls, fname: str, group_path: str = "", - custom_decoders: List[Callable] = None, + custom_decoders: Optional[list[Callable]] = None, **parse_obj_kwargs, ) -> Tidy3dBaseModel: """Loads :class:`Tidy3dBaseModel` instance to .hdf5 file. @@ -698,7 +700,7 @@ def from_hdf5( ) return cls.parse_obj(model_dict, **parse_obj_kwargs) - def to_hdf5(self, fname: str, custom_encoders: List[Callable] = None) -> None: + def to_hdf5(self, fname: str, custom_encoders: Optional[list[Callable]] = None) -> None: """Exports :class:`Tidy3dBaseModel` instance to .hdf5 file. Parameters @@ -749,7 +751,7 @@ def add_data_to_file(data_dict: dict, group_path: str = "") -> None: @classmethod def dict_from_hdf5_gz( - cls, fname: str, group_path: str = "", custom_decoders: List[Callable] = None + cls, fname: str, group_path: str = "", custom_decoders: Optional[list[Callable]] = None ) -> dict: """Loads a dictionary containing the model contents from a .hdf5.gz file. @@ -790,7 +792,7 @@ def from_hdf5_gz( cls, fname: str, group_path: str = "", - custom_decoders: List[Callable] = None, + custom_decoders: Optional[list[Callable]] = None, **parse_obj_kwargs, ) -> Tidy3dBaseModel: """Loads :class:`Tidy3dBaseModel` instance to .hdf5.gz file. @@ -820,7 +822,7 @@ def from_hdf5_gz( ) return cls.parse_obj(model_dict, **parse_obj_kwargs) - def to_hdf5_gz(self, fname: str, custom_encoders: List[Callable] = None) -> None: + def to_hdf5_gz(self, fname: str, custom_encoders: Optional[list[Callable]] = None) -> None: """Exports :class:`Tidy3dBaseModel` instance to .hdf5.gz file. Parameters @@ -873,7 +875,7 @@ def check_equal(dict1: dict, dict2: dict) -> bool: return False # loop through elements in each dict - for key in dict1.keys(): + for key in dict1: # noqa: PLC0206 val1 = dict1[key] val2 = dict2[key] @@ -948,7 +950,7 @@ def make_json_compatible(json_string: str) -> str: json_string = make_json_compatible(json_string) return json_string - def strip_traced_fields( + def _strip_traced_fields( self, starting_path: tuple[str] = (), include_untraced_data_arrays: bool = False ) -> AutogradFieldMap: """Extract a dictionary mapping paths in the model to the data traced by ``autograd``. @@ -984,12 +986,12 @@ def handle_value(x: Any, path: tuple[str, ...]) -> None: # for sequences, add (i,) to the path and handle each value individually elif isinstance(x, (list, tuple)): for i, val in enumerate(x): - handle_value(val, path=path + (i,)) + handle_value(val, path=(*path, i)) # for dictionaries, add the (key,) to the path and handle each value individually elif isinstance(x, dict): for key, val in x.items(): - handle_value(val, path=path + (key,)) + handle_value(val, path=(*path, key)) # recursively parse the dictionary of this object self_dict = self.dict() @@ -1004,7 +1006,7 @@ def handle_value(x: Any, path: tuple[str, ...]) -> None: # convert the resulting field_mapping to an autograd-traced dictionary return dict_ag(field_mapping) - def insert_traced_fields(self, field_mapping: AutogradFieldMap) -> Tidy3dBaseModel: + def _insert_traced_fields(self, field_mapping: AutogradFieldMap) -> Tidy3dBaseModel: """Recursively insert a map of paths to autograd-traced fields into a copy of this obj.""" self_dict = self.dict() @@ -1037,7 +1039,7 @@ def to_static(self) -> Tidy3dBaseModel: """Version of object with all autograd-traced fields removed.""" # get dictionary of all traced fields - field_mapping = self.strip_traced_fields() + field_mapping = self._strip_traced_fields() # shortcut to just return self if no tracers found, for performance if not field_mapping: @@ -1047,7 +1049,7 @@ def to_static(self) -> Tidy3dBaseModel: field_mapping_static = {key: get_static(val) for key, val in field_mapping.items()} # insert the static values into a copy of self - return self.insert_traced_fields(field_mapping_static) + return self._insert_traced_fields(field_mapping_static) @classmethod def add_type_field(cls) -> None: @@ -1132,7 +1134,7 @@ def generate_docstring(cls) -> str: doc += "\n" cls.__doc__ = doc - def get_submodels_by_hash(self) -> Dict[int, List[Union[str, Tuple[str, int]]]]: + def get_submodels_by_hash(self) -> dict[int, list[Union[str, tuple[str, int]]]]: """Return a dictionary of this object's sub-models indexed by their hash values.""" fields = {} for key in self.__fields__: @@ -1166,7 +1168,7 @@ def get_submodels_by_hash(self) -> Dict[int, List[Union[str, Tuple[str, int]]]]: @staticmethod def _scientific_notation( min_val: float, max_val: float, min_digits: int = 4 - ) -> Tuple[str, str]: + ) -> tuple[str, str]: """ Convert numbers to scientific notation, displaying only digits up to the point of difference, with a minimum number of significant digits specified by `min_digits`. diff --git a/tidy3d/components/base_sim/data/monitor_data.py b/tidy3d/components/base_sim/data/monitor_data.py index 86d2f0717b..18fb82728a 100644 --- a/tidy3d/components/base_sim/data/monitor_data.py +++ b/tidy3d/components/base_sim/data/monitor_data.py @@ -6,8 +6,8 @@ import pydantic.v1 as pd -from ...data.dataset import Dataset -from ..monitor import AbstractMonitor +from tidy3d.components.base_sim.monitor import AbstractMonitor +from tidy3d.components.data.dataset import Dataset class AbstractMonitorData(Dataset, ABC): diff --git a/tidy3d/components/base_sim/data/sim_data.py b/tidy3d/components/base_sim/data/sim_data.py index 88644a26c6..86e752cc55 100644 --- a/tidy3d/components/base_sim/data/sim_data.py +++ b/tidy3d/components/base_sim/data/sim_data.py @@ -3,18 +3,19 @@ from __future__ import annotations from abc import ABC -from typing import Dict, Tuple, Union +from typing import Union import numpy as np import pydantic.v1 as pd import xarray as xr -from ....exceptions import DataError, Tidy3dKeyError, ValidationError -from ...base import Tidy3dBaseModel, skip_if_fields_missing -from ...data.utils import UnstructuredGridDatasetType -from ...types import FieldVal -from ..simulation import AbstractSimulation -from .monitor_data import AbstractMonitorData +from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing +from tidy3d.components.base_sim.data.monitor_data import AbstractMonitorData +from tidy3d.components.base_sim.simulation import AbstractSimulation +from tidy3d.components.data.utils import UnstructuredGridDatasetType +from tidy3d.components.monitor import AbstractMonitor +from tidy3d.components.types import FieldVal +from tidy3d.exceptions import DataError, Tidy3dKeyError, ValidationError class AbstractSimulationData(Tidy3dBaseModel, ABC): @@ -28,7 +29,7 @@ class AbstractSimulationData(Tidy3dBaseModel, ABC): description="Original :class:`AbstractSimulation` associated with the data.", ) - data: Tuple[AbstractMonitorData, ...] = pd.Field( + data: tuple[AbstractMonitorData, ...] = pd.Field( ..., title="Monitor Data", description="List of :class:`AbstractMonitorData` instances " @@ -47,19 +48,19 @@ def __getitem__(self, monitor_name: str) -> AbstractMonitorData: return monitor_data.symmetry_expanded_copy @property - def monitor_data(self) -> Dict[str, AbstractMonitorData]: + def monitor_data(self) -> dict[str, AbstractMonitorData]: """Dictionary mapping monitor name to its associated :class:`AbstractMonitorData`.""" return {monitor_data.monitor.name: monitor_data for monitor_data in self.data} - @pd.validator("data", always=True) - @skip_if_fields_missing(["simulation"]) - def data_monitors_match_sim(cls, val, values): + @pd.root_validator(skip_on_failure=True) + def data_monitors_match_sim(cls, values): """Ensure each :class:`AbstractMonitorData` in ``.data`` corresponds to a monitor in ``.simulation``. """ sim = values.get("simulation") + data = values.get("data") - for mnt_data in val: + for mnt_data in data: try: monitor_name = mnt_data.monitor.name sim.get_monitor_by_name(monitor_name) @@ -68,7 +69,7 @@ def data_monitors_match_sim(cls, val, values): f"Data with monitor name '{monitor_name}' supplied " f"but not found in the original '{sim.type}'." ) from exc - return val + return values @pd.validator("data", always=True) @skip_if_fields_missing(["simulation"]) @@ -127,3 +128,7 @@ def _field_component_value( ) return field_value + + def get_monitor_by_name(self, name: str) -> AbstractMonitor: + """Return monitor named 'name'.""" + return self.simulation.get_monitor_by_name(name) diff --git a/tidy3d/components/base_sim/monitor.py b/tidy3d/components/base_sim/monitor.py index e5355e5679..e29f707adc 100644 --- a/tidy3d/components/base_sim/monitor.py +++ b/tidy3d/components/base_sim/monitor.py @@ -1,16 +1,17 @@ """Abstract bases for classes that define how data is recorded from simulation.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Tuple import numpy as np import pydantic.v1 as pd -from ..base import cached_property -from ..geometry.base import Box -from ..types import ArrayFloat1D, Axis, Numpy -from ..validators import _warn_unsupported_traced_argument -from ..viz import PlotParams, plot_params_monitor +from tidy3d.components.base import cached_property +from tidy3d.components.geometry.base import Box +from tidy3d.components.types import ArrayFloat1D, Axis, Numpy +from tidy3d.components.validators import _warn_unsupported_traced_argument +from tidy3d.components.viz import PlotParams, plot_params_monitor class AbstractMonitor(Box, ABC): @@ -88,7 +89,7 @@ def downsample(self, arr: Numpy, axis: Axis) -> Numpy: inds = np.append(inds, size - 1) return arr[inds] - def downsampled_num_cells(self, num_cells: Tuple[int, int, int]) -> Tuple[int, int, int]: + def downsampled_num_cells(self, num_cells: tuple[int, int, int]) -> tuple[int, int, int]: """Given a tuple of the number of cells spanned by the monitor along each dimension, return the number of cells one would have after downsampling based on ``interval_space``. """ diff --git a/tidy3d/components/base_sim/simulation.py b/tidy3d/components/base_sim/simulation.py index 0d3dfa228e..f6f0e8c903 100644 --- a/tidy3d/components/base_sim/simulation.py +++ b/tidy3d/components/base_sim/simulation.py @@ -3,31 +3,35 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, Tuple +from typing import Optional import autograd.numpy as anp import pydantic.v1 as pd -from ...exceptions import Tidy3dKeyError -from ...log import log -from ...version import __version__ -from ..base import cached_property, skip_if_fields_missing -from ..geometry.base import Box -from ..medium import Medium, MediumType3D -from ..scene import Scene -from ..structure import Structure -from ..types import TYPE_TAG_STR, Ax, Axis, Bound, LengthUnit, Symmetry -from ..validators import ( +from tidy3d.components.base import cached_property, skip_if_fields_missing +from tidy3d.components.geometry.base import Box +from tidy3d.components.medium import Medium, MediumType3D +from tidy3d.components.scene import Scene +from tidy3d.components.structure import Structure +from tidy3d.components.types import ( + TYPE_TAG_STR, + Ax, + Axis, + Bound, + LengthUnit, + PriorityMode, + Symmetry, +) +from tidy3d.components.validators import ( _warn_unsupported_traced_argument, assert_objects_in_sim_bounds, assert_unique_names, ) -from ..viz import ( - PlotParams, - add_ax_if_none, - equal_aspect, - plot_params_symmetry, -) +from tidy3d.components.viz import PlotParams, add_ax_if_none, equal_aspect, plot_params_symmetry +from tidy3d.exceptions import Tidy3dKeyError +from tidy3d.log import log +from tidy3d.version import __version__ + from .monitor import AbstractMonitor @@ -44,7 +48,7 @@ class AbstractSimulation(Box, ABC): Background medium of simulation, defaults to vacuum if not specified. """ - structures: Tuple[Structure, ...] = pd.Field( + structures: tuple[Structure, ...] = pd.Field( (), title="Structures", description="Tuple of structures present in simulation. " @@ -73,7 +77,7 @@ class AbstractSimulation(Box, ABC): ) """ - symmetry: Tuple[Symmetry, Symmetry, Symmetry] = pd.Field( + symmetry: tuple[Symmetry, Symmetry, Symmetry] = pd.Field( (0, 0, 0), title="Symmetries", description="Tuple of integers defining reflection symmetry across a plane " @@ -81,7 +85,7 @@ class AbstractSimulation(Box, ABC): "at the simulation center of each axis, respectively. ", ) - sources: Tuple[None, ...] = pd.Field( + sources: tuple[None, ...] = pd.Field( (), title="Sources", description="Sources in the simulation.", @@ -93,7 +97,7 @@ class AbstractSimulation(Box, ABC): description="Specification of boundary conditions.", ) - monitors: Tuple[None, ...] = pd.Field( + monitors: tuple[None, ...] = pd.Field( (), title="Monitors", description="Monitors in the simulation. ", @@ -119,6 +123,15 @@ class AbstractSimulation(Box, ABC): "include the desired unit specifier in labels.", ) + structure_priority_mode: PriorityMode = pd.Field( + "equal", + title="Structure Priority Setting", + description="This field only affects structures of `priority=None`. " + "If `equal`, the priority of those structures is set to 0; if `conductor`, " + "the priority of structures made of `LossyMetalMedium` is set to 90, " + "`PECMedium` to 100, and others to 0.", + ) + """ Validating setup """ @pd.root_validator(pre=True) @@ -182,7 +195,6 @@ def _post_init_validators(self) -> None: def validate_pre_upload(self) -> None: """Validate the fully initialized simulation is ok for upload to our servers.""" - pass """ Accounting """ @@ -191,7 +203,10 @@ def scene(self) -> Scene: """Scene instance associated with the simulation.""" return Scene( - medium=self.medium, structures=self.structures, plot_length_units=self.plot_length_units + medium=self.medium, + structures=self.structures, + plot_length_units=self.plot_length_units, + structure_priority_mode=self.structure_priority_mode, ) def get_monitor_by_name(self, name: str) -> AbstractMonitor: @@ -227,14 +242,14 @@ def simulation_structure(self) -> Structure: @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - source_alpha: float = None, - monitor_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, **patch_kwargs, ) -> Ax: @@ -292,12 +307,12 @@ def plot( @add_ax_if_none def plot_sources( self, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's sources on a plane defined by one nonzero x,y,z coordinate. @@ -340,12 +355,12 @@ def plot_sources( @add_ax_if_none def plot_monitors( self, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's monitors on a plane defined by one nonzero x,y,z coordinate. @@ -388,11 +403,11 @@ def plot_monitors( @add_ax_if_none def plot_symmetries( self, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's symmetries on a plane defined by one nonzero x,y,z coordinate. @@ -463,9 +478,9 @@ def _make_symmetry_box(self, sym_axis: Axis) -> Box: @add_ax_if_none def plot_boundaries( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **kwargs, ) -> Ax: @@ -497,12 +512,12 @@ def plot_boundaries( @add_ax_if_none def plot_structures( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, fill: bool = True, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. @@ -541,16 +556,16 @@ def plot_structures( @add_ax_if_none def plot_structures_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. @@ -608,15 +623,15 @@ def plot_structures_eps( @add_ax_if_none def plot_structures_heat_conductivity( self, - x: float = None, - y: float = None, - z: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. diff --git a/tidy3d/components/base_sim/source.py b/tidy3d/components/base_sim/source.py index cdaff53d66..f1630c41c0 100644 --- a/tidy3d/components/base_sim/source.py +++ b/tidy3d/components/base_sim/source.py @@ -6,9 +6,9 @@ import pydantic.v1 as pydantic -from ..base import Tidy3dBaseModel -from ..validators import validate_name_str -from ..viz import PlotParams +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.validators import validate_name_str +from tidy3d.components.viz import PlotParams class AbstractSource(Tidy3dBaseModel, ABC): diff --git a/tidy3d/components/bc_placement.py b/tidy3d/components/bc_placement.py index c59c11962e..1f48a94fbf 100644 --- a/tidy3d/components/bc_placement.py +++ b/tidy3d/components/bc_placement.py @@ -3,11 +3,12 @@ from __future__ import annotations from abc import ABC -from typing import Tuple, Union +from typing import Union import pydantic.v1 as pd -from ..exceptions import SetupError +from tidy3d.exceptions import SetupError + from .base import Tidy3dBaseModel from .types import BoxSurface @@ -38,7 +39,7 @@ class StructureStructureInterface(AbstractBCPlacement): >>> bc_placement = StructureStructureInterface(structures=["box", "sphere"]) """ - structures: Tuple[str, str] = pd.Field( + structures: tuple[str, str] = pd.Field( title="Structures", description="Names of two structures.", ) @@ -61,7 +62,7 @@ class MediumMediumInterface(AbstractBCPlacement): >>> bc_placement = MediumMediumInterface(mediums=["dieletric", "metal"]) """ - mediums: Tuple[str, str] = pd.Field( + mediums: tuple[str, str] = pd.Field( title="Mediums", description="Names of two mediums.", ) @@ -82,7 +83,7 @@ class SimulationBoundary(AbstractBCPlacement): >>> bc_placement = SimulationBoundary(surfaces=["x-", "x+"]) """ - surfaces: Tuple[BoxSurface, ...] = pd.Field( + surfaces: tuple[BoxSurface, ...] = pd.Field( ("x-", "x+", "y-", "y+", "z-", "z+"), title="Surfaces", description="Surfaces of simulation domain where to apply boundary conditions.", @@ -102,7 +103,7 @@ class StructureSimulationBoundary(AbstractBCPlacement): description="Name of the structure.", ) - surfaces: Tuple[BoxSurface, ...] = pd.Field( + surfaces: tuple[BoxSurface, ...] = pd.Field( ("x-", "x+", "y-", "y+", "z-", "z+"), title="Surfaces", description="Surfaces of simulation domain where to apply boundary conditions.", diff --git a/tidy3d/components/beam.py b/tidy3d/components/beam.py index 4a6f632466..ff42abf31b 100644 --- a/tidy3d/components/beam.py +++ b/tidy3d/components/beam.py @@ -1,13 +1,16 @@ """Classes for creating data based on analytic beams like plane wave, Gaussian beam, and astigmatic Gaussian beam.""" +from __future__ import annotations + from abc import abstractmethod -from typing import Optional, Tuple, Union +from typing import Literal, Optional, Union import autograd.numpy as np import pydantic.v1 as pd -from ..constants import C_0, ETA_0, HERTZ, MICROMETER, RADIAN +from tidy3d.constants import C_0, ETA_0, HERTZ, MICROMETER, RADIAN + from .base import cached_property from .data.data_array import ScalarFieldDataArray from .data.monitor_data import FieldData @@ -16,7 +19,7 @@ from .medium import Medium, MediumType from .monitor import FieldMonitor from .source.field import FixedAngleSpec, FixedInPlaneKSpec -from .types import TYPE_TAG_STR, Direction, FreqArray, Literal, Numpy +from .types import TYPE_TAG_STR, Direction, FreqArray, Numpy from .validators import assert_plane DEFAULT_RESOLUTION = 200 @@ -156,7 +159,7 @@ def _field_data_on_grid(self, grid: Grid, background_n: Numpy, colocate=True) -> # Get the current field component field_vals = field_vals[comp % 3] # Make the ScalarFieldDataArray for the current component - coords = dict(x=x, y=y, z=z, f=np.array(self.freqs)) + coords = {"x": x, "y": y, "z": z, "f": np.array(self.freqs)} field_data = ScalarFieldDataArray(field_vals, coords=coords) scalar_fields[field] = field_data @@ -167,7 +170,6 @@ def scalar_field(self, points: Numpy, background_n: float) -> Numpy: """Scalar field corresponding to the analytic beam in coordinate system such that the propagation direction is z and the ``E``-field is entirely ``x``-polarized. The field is computed on an unstructured array ``points`` of shape ``(3, ...)``.""" - pass def analytic_beam_z_normal( self, points: Numpy, background_n: float, field: Literal["E", "H"] @@ -316,14 +318,14 @@ def _angle_theta_actual(self, background_n: Numpy) -> Numpy: k0 = 2 * np.pi * np.array(self.freqs) / C_0 * background_n kx, ky = self.in_plane_k(background_n) k_perp = np.sqrt(kx**2 + ky**2) - return np.real(np.arcsin(k_perp / k0)) + return np.real(np.arcsin(k_perp / k0)) * np.sign(self.angle_theta) def _rotate_points_z(self, points: Numpy, background_n: Numpy) -> Numpy: """Rotate points to new coordinates where z is the propagation axis.""" if self.as_fixed_angle_source: # For fixed-angle, we do not rotate the points return points - elif isinstance(self.angular_spec, FixedInPlaneKSpec): + if isinstance(self.angular_spec, FixedInPlaneKSpec): # For fixed in-plane k, the rotation is angle-dependent points = self.rotate_points(points, [0, 0, 1], -self.angle_phi) angle_theta_actual = self._angle_theta_actual(background_n=background_n) @@ -373,7 +375,7 @@ class GaussianBeamProfile(BeamProfile): units=MICROMETER, ) - def beam_params(self, z: Numpy, k0: Numpy) -> Tuple[Numpy, Numpy, Numpy]: + def beam_params(self, z: Numpy, k0: Numpy) -> tuple[Numpy, Numpy, Numpy]: """Compute the parameters needed to evaluate a Gaussian beam at z. Parameters @@ -420,14 +422,14 @@ class AstigmaticGaussianBeamProfile(BeamProfile): See also :class:`.AstigmaticGaussianBeam`. """ - waist_sizes: Tuple[pd.PositiveFloat, pd.PositiveFloat] = pd.Field( + waist_sizes: tuple[pd.PositiveFloat, pd.PositiveFloat] = pd.Field( (1.0, 1.0), title="Waist sizes", description="Size of the beam at the waist in the local x and y directions.", units=MICROMETER, ) - waist_distances: Tuple[float, float] = pd.Field( + waist_distances: tuple[float, float] = pd.Field( (0.0, 0.0), title="Waist distances", description="Distance to the beam waist along the propagation direction " @@ -439,7 +441,7 @@ class AstigmaticGaussianBeamProfile(BeamProfile): units=MICROMETER, ) - def beam_params(self, z: Numpy, k0: Numpy) -> Tuple[Numpy, Numpy, Numpy, Numpy]: + def beam_params(self, z: Numpy, k0: Numpy) -> tuple[Numpy, Numpy, Numpy, Numpy]: """Compute the parameters needed to evaluate an astigmatic Gaussian beam at z. Parameters diff --git a/tidy3d/components/boundary.py b/tidy3d/components/boundary.py index 2e0acc62fa..45e3924ac7 100644 --- a/tidy3d/components/boundary.py +++ b/tidy3d/components/boundary.py @@ -3,20 +3,45 @@ from __future__ import annotations from abc import ABC -from typing import List, Tuple, Union +from typing import Union import numpy as np import pydantic.v1 as pd -from ..constants import EPSILON_0, MU_0, PML_SIGMA -from ..exceptions import DataError, SetupError -from ..log import log +from tidy3d.constants import EPSILON_0, MU_0, PML_SIGMA +from tidy3d.exceptions import DataError, SetupError +from tidy3d.log import log + from .base import Tidy3dBaseModel, cached_property from .medium import Medium from .source.field import TFSF, GaussianBeam, ModeSource, PlaneWave from .types import TYPE_TAG_STR, Axis, Complex MIN_NUM_PML_LAYERS = 6 +MIN_NUM_STABLE_PML_LAYERS = 6 +MIN_NUM_ABSORBER_LAYERS = 6 + + +def warn_num_layers_factory(min_num_layers: int, descr: str): + """Several similar classes defined have a ``num_layers`` data member, and they generate + similar warning messages when ``num_layers`` is too small. This function creates a pydantic + validator which can be shared with all of these classes to create these warning messages.""" + + @pd.validator("num_layers", allow_reuse=True, always=True) + def _warn_num_layers(cls, val): + if val < min_num_layers: + cls_name = cls.__name__ + log.warning( + f"A {descr} ({cls_name}) boundary was created with {val} layers. " + f"{cls_name}s with less than {min_num_layers} layers are highly subject to " + "unwanted numerical artifacts. We strongly recommend " + "increasing the number of layers. For more details refer to: " + f"'https://docs.flexcompute.com/projects/tidy3d/en/latest/api/_autosummary/tidy3d.{cls_name}.html'.", + log_once=True, + ) + return val + + return _warn_num_layers class BoundaryEdge(ABC, Tidy3dBaseModel): @@ -266,7 +291,7 @@ class AbsorberSpec(BoundaryEdge): ..., title="Number of Layers", description="Number of layers of standard PML.", - ge=MIN_NUM_PML_LAYERS, + ge=1, ) parameters: AbsorberParams = pd.Field( ..., @@ -383,7 +408,7 @@ class PML(AbsorberSpec): 12, title="Number of Layers", description="Number of layers of standard PML.", - ge=MIN_NUM_PML_LAYERS, + ge=1, ) parameters: PMLParams = pd.Field( @@ -392,6 +417,10 @@ class PML(AbsorberSpec): description="Parameters of the complex frequency-shifted absorption poles.", ) + _warn_num_layers = warn_num_layers_factory( + min_num_layers=MIN_NUM_PML_LAYERS, descr="perfectly-matched layer" + ) + class StablePML(AbsorberSpec): """Specifies a 'stable' PML along a single dimension. @@ -421,7 +450,7 @@ class StablePML(AbsorberSpec): 40, title="Number of Layers", description="Number of layers of 'stable' PML.", - ge=MIN_NUM_PML_LAYERS, + ge=1, ) parameters: PMLParams = pd.Field( @@ -430,6 +459,10 @@ class StablePML(AbsorberSpec): description="'Stable' parameters of the complex frequency-shifted absorption poles.", ) + _warn_num_layers = warn_num_layers_factory( + min_num_layers=MIN_NUM_STABLE_PML_LAYERS, descr="stable perfectly-matched layer" + ) + class Absorber(AbsorberSpec): """Specifies an adiabatic absorber along a single dimension. @@ -474,7 +507,7 @@ class Absorber(AbsorberSpec): 40, title="Number of Layers", description="Number of layers of absorber to add to + and - boundaries.", - ge=MIN_NUM_PML_LAYERS, + ge=1, ) parameters: AbsorberParams = pd.Field( @@ -483,6 +516,10 @@ class Absorber(AbsorberSpec): description="Adiabatic absorber parameters.", ) + _warn_num_layers = warn_num_layers_factory( + min_num_layers=MIN_NUM_ABSORBER_LAYERS, descr="absorber" + ) + # pml types allowed in simulation init PMLTypes = Union[PML, StablePML, Absorber, None] @@ -906,7 +943,7 @@ def all_sides(cls, boundary: BoundaryEdge): ) @cached_property - def to_list(self) -> List[Tuple[BoundaryEdgeType, BoundaryEdgeType]]: + def to_list(self) -> list[tuple[BoundaryEdgeType, BoundaryEdgeType]]: """Returns edge-wise boundary conditions along each dimension for internal use.""" return [ (self.x.minus, self.x.plus), @@ -917,12 +954,12 @@ def to_list(self) -> List[Tuple[BoundaryEdgeType, BoundaryEdgeType]]: @cached_property def flipped_bloch_vecs(self) -> BoundarySpec: """Return a copy of the instance where all Bloch vectors are multiplied by -1.""" - bound_dims = dict(x=self.x.copy(), y=self.y.copy(), z=self.z.copy()) + bound_dims = {"x": self.x.copy(), "y": self.y.copy(), "z": self.z.copy()} for dim_key, bound_dim in bound_dims.items(): - bound_edges = dict(plus=bound_dim.plus.copy(), minus=bound_dim.minus.copy()) + bound_edges = {"plus": bound_dim.plus.copy(), "minus": bound_dim.minus.copy()} for edge_key, bound_edge in bound_edges.items(): if isinstance(bound_edge, BlochBoundary): new_bloch_vec = -1 * bound_edge.bloch_vec - bound_edges[edge_key] = bound_edge.copy(update=dict(bloch_vec=new_bloch_vec)) + bound_edges[edge_key] = bound_edge.copy(update={"bloch_vec": new_bloch_vec}) bound_dims[dim_key] = bound_edges return self.copy(update=bound_dims) diff --git a/tidy3d/components/data/data_array.py b/tidy3d/components/data/data_array.py index 9cabd11796..af66543b9a 100644 --- a/tidy3d/components/data/data_array.py +++ b/tidy3d/components/data/data_array.py @@ -3,7 +3,8 @@ from __future__ import annotations from abc import ABC -from typing import Any, Dict, List, Mapping, Union +from collections.abc import Mapping +from typing import Any, Optional, Union import autograd.numpy as anp import h5py @@ -17,8 +18,11 @@ from xarray.core.utils import OrderedSet, either_dict_or_kwargs from xarray.core.variable import as_variable -from ...compat import alignment -from ...constants import ( +from tidy3d.compat import alignment +from tidy3d.components.autograd import TidyArrayBox, get_static, interpn, is_tidy_box +from tidy3d.components.geometry.bound_ops import bounds_contains +from tidy3d.components.types import Axis, Bound +from tidy3d.constants import ( HERTZ, MICROMETER, PICOSECOND_PER_NANOMETER_PER_KILOMETER, @@ -26,9 +30,7 @@ SECOND, WATT, ) -from ...exceptions import DataError, FileError -from ..autograd import TidyArrayBox, get_static, interpn, is_tidy_box -from ..types import Axis, Bound +from tidy3d.exceptions import DataError, FileError # maps the dimension names to their attributes DIM_ATTRS = { @@ -68,7 +70,7 @@ class DataArray(xr.DataArray): # stores an ordered tuple of strings corresponding to the data dimensions _dims = () # stores a dictionary of attributes corresponding to the data values - _data_attrs: Dict[str, str] = {} + _data_attrs: dict[str, str] = {} def __init__(self, data, *args, **kwargs): # if data is a vanilla autograd box, convert to our box @@ -117,7 +119,7 @@ def assign_data_attrs(cls, val): val.attrs[attr_name] = attr return val - def _interp_validator(self, field_name: str = None) -> None: + def _interp_validator(self, field_name: Optional[str] = None) -> None: """Ensure the data can be interpolated or selected by checking for duplicate coordinates. NOTE @@ -151,17 +153,17 @@ def assign_coord_attrs(cls, val): def __modify_schema__(cls, field_schema): """Sets the schema of DataArray object.""" - schema = dict( - title="DataArray", - type="xr.DataArray", - properties=dict( - _dims=dict( - title="_dims", - type="Tuple[str, ...]", - ), - ), - required=["_dims"], - ) + schema = { + "title": "DataArray", + "type": "xr.DataArray", + "properties": { + "_dims": { + "title": "_dims", + "type": "Tuple[str, ...]", + }, + }, + "required": ["_dims"], + } field_schema.update(schema) @classmethod @@ -260,7 +262,7 @@ def __hash__(self) -> int: token_str = dask.base.tokenize(self) return hash(token_str) - def multiply_at(self, value: complex, coord_name: str, indices: List[int]) -> Self: + def multiply_at(self, value: complex, coord_name: str, indices: list[int]) -> Self: """Multiply self by value at indices.""" if isbox(self.data) or isbox(value): return self._ag_multiply_at(value, coord_name, indices) @@ -269,7 +271,7 @@ def multiply_at(self, value: complex, coord_name: str, indices: List[int]) -> Se self_mult[{coord_name: indices}] *= value return self_mult - def _ag_multiply_at(self, value: complex, coord_name: str, indices: List[int]) -> Self: + def _ag_multiply_at(self, value: complex, coord_name: str, indices: list[int]) -> Self: """Autograd multiply_at override when tracing.""" key = {coord_name: indices} _, index_tuple, _ = self.variable._broadcast_indexes(key) @@ -627,7 +629,7 @@ def sel_inside(self, bounds: Bound) -> SpatialDataArray: return sorted_self.isel(x=inds_list[0], y=inds_list[1], z=inds_list[2]) - def does_cover(self, bounds: Bound) -> bool: + def does_cover(self, bounds: Bound, rtol: float = 0.0, atol: float = 0.0) -> bool: """Check whether data fully covers specified by ``bounds`` spatial region. If data contains only one point along a given direction, then it is assumed the data is constant along that direction and coverage is not checked. @@ -637,6 +639,10 @@ def does_cover(self, bounds: Bound) -> bool: ---------- bounds : Tuple[float, float, float], Tuple[float, float float] Min and max bounds packaged as ``(minx, miny, minz), (maxx, maxy, maxz)``. + rtol : float = 0.0 + Relative tolerance for comparing bounds + atol : float = 0.0 + Absolute tolerance for comparing bounds Returns ------- @@ -647,12 +653,19 @@ def does_cover(self, bounds: Bound) -> bool: raise DataError( "Min and max bounds must be packaged as '(minx, miny, minz), (maxx, maxy, maxz)'." ) - - coords = (self.x, self.y, self.z) - return all( - (np.min(coord) <= smin and np.max(coord) >= smax) or len(coord) == 1 - for coord, smin, smax in zip(coords, bounds[0], bounds[1]) - ) + xyz = [self.x, self.y, self.z] + self_min = [0] * 3 + self_max = [0] * 3 + for dim in range(3): + coords = xyz[dim] + if len(coords) == 1: + self_min[dim] = bounds[0][dim] + self_max[dim] = bounds[1][dim] + else: + self_min[dim] = np.min(coords) + self_max[dim] = np.max(coords) + self_bounds = (tuple(self_min), tuple(self_max)) + return bounds_contains(self_bounds, bounds, rtol=rtol, atol=atol) class SpatialDataArray(AbstractSpatialDataArray): @@ -1162,9 +1175,9 @@ class SteadyVoltageDataArray(DataArray): class PointDataArray(DataArray): - """A two-dimensional array that stores coordinates of a collection of points. + """A two-dimensional array that stores coordinates/field components for a collection of points. Dimension ``index`` denotes the index of a point in the collection, and dimension ``axis`` - denotes the point's coordinate along that axis. + denotes the field component (or point coordinate) in that direction. Example ------- @@ -1175,6 +1188,14 @@ class PointDataArray(DataArray): >>> point3 = point_array.sel(index=3) >>> # get x coordinates of all points >>> x_coords = point_array.sel(axis=0) + >>> + >>> field_da = PointDataArray( + ... np.random.random((120, 3)), coords=dict(index=np.arange(120), axis=np.arange(3)), + ... ) + >>> # get field of point number 90 + >>> field_point90 = field_da.sel(index=90) + >>> # get z component of all points + >>> z_field = field_da.sel(axis=2) """ __slots__ = () @@ -1236,6 +1257,36 @@ class IndexedVoltageDataArray(DataArray): _dims = ("index", "voltage") +class IndexedTimeDataArray(DataArray): + """Stores a two-dimensional array with coordinates ``index`` and ``t``, where + ``index`` is usually associated with ``PointDataArray`` and ``t`` indicates at what + simulated time the data was obtained. + + Example + ------- + >>> indexed_array = IndexedTimeDataArray( + ... (1+1j) * np.random.random((3,2)), coords=dict(index=np.arange(3), t=[0, 1]) + ... ) + """ + + __slots__ = () + _dims = ("index", "t") + + +class IndexedFieldVoltageDataArray(DataArray): + """Stores indexed values of vector fields for different voltages. It is typically used + in conjuction with a ``PointDataArray`` to store point-associated vector data. + Example + ------- + >>> indexed_array = IndexedFieldVoltageDataArray( + ... (1+1j) * np.random.random((4,3,2)), coords=dict(index=np.arange(4), axis=np.arange(3), voltage=[-1, 1]) + ... ) + """ + + __slots__ = () + _dims = ("index", "axis", "voltage") + + class SpatialVoltageDataArray(AbstractSpatialDataArray): """Spatial distribution with voltage mapping. @@ -1253,6 +1304,11 @@ class SpatialVoltageDataArray(AbstractSpatialDataArray): _dims = ("x", "y", "z", "voltage") +class PerturbationCoefficientDataArray(DataArray): + __slots__ = () + _dims = ("wvl", "coeff") + + DATA_ARRAY_TYPES = [ SpatialDataArray, ScalarFieldDataArray, @@ -1285,8 +1341,18 @@ class SpatialVoltageDataArray(AbstractSpatialDataArray): PointDataArray, CellDataArray, IndexedDataArray, + IndexedFieldVoltageDataArray, IndexedVoltageDataArray, + SpatialVoltageDataArray, + PerturbationCoefficientDataArray, + IndexedTimeDataArray, ] DATA_ARRAY_MAP = {data_array.__name__: data_array for data_array in DATA_ARRAY_TYPES} -IndexedDataArrayTypes = Union[IndexedDataArray, IndexedVoltageDataArray] +IndexedDataArrayTypes = Union[ + IndexedDataArray, + IndexedVoltageDataArray, + IndexedTimeDataArray, + IndexedFieldVoltageDataArray, + PointDataArray, +] diff --git a/tidy3d/components/data/dataset.py b/tidy3d/components/data/dataset.py index de64f657f4..697a5d4805 100644 --- a/tidy3d/components/data/dataset.py +++ b/tidy3d/components/data/dataset.py @@ -3,17 +3,18 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, Callable, Dict, Optional, Union, get_args +from typing import Any, Callable, Optional, Union, get_args import numpy as np import pydantic.v1 as pd import xarray as xr -from ...constants import C_0, PICOSECOND_PER_NANOMETER_PER_KILOMETER, UnitScaling -from ...exceptions import DataError -from ...log import log -from ..base import Tidy3dBaseModel -from ..types import Axis, xyz +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.types import Axis, xyz +from tidy3d.constants import C_0, PICOSECOND_PER_NANOMETER_PER_KILOMETER, UnitScaling +from tidy3d.exceptions import DataError +from tidy3d.log import log + from .data_array import ( DataArray, EMEScalarFieldDataArray, @@ -44,7 +45,7 @@ class AbstractFieldDataset(Dataset, ABC): @property @abstractmethod - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" def apply_phase(self, phase: float) -> AbstractFieldDataset: @@ -60,15 +61,15 @@ def apply_phase(self, phase: float) -> AbstractFieldDataset: @property @abstractmethod - def grid_locations(self) -> Dict[str, str]: + def grid_locations(self) -> dict[str, str]: """Maps field components to the string key of their grid locations on the yee lattice.""" @property @abstractmethod - def symmetry_eigenvalues(self) -> Dict[str, Callable[[Axis], float]]: + def symmetry_eigenvalues(self) -> dict[str, Callable[[Axis], float]]: """Maps field components to their (positive) symmetry eigenvalues.""" - def package_colocate_results(self, centered_fields: Dict[str, ScalarFieldDataArray]) -> Any: + def package_colocate_results(self, centered_fields: dict[str, ScalarFieldDataArray]) -> Any: """How to package the dictionary of fields computed via self.colocate().""" return xr.Dataset(centered_fields) @@ -182,7 +183,7 @@ class ElectromagneticFieldDataset(AbstractFieldDataset, ABC): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" fields = { "Ex": self.Ex, @@ -195,22 +196,22 @@ def field_components(self) -> Dict[str, DataArray]: return {field_name: field for field_name, field in fields.items() if field is not None} @property - def grid_locations(self) -> Dict[str, str]: + def grid_locations(self) -> dict[str, str]: """Maps field components to the string key of their grid locations on the yee lattice.""" - return dict(Ex="Ex", Ey="Ey", Ez="Ez", Hx="Hx", Hy="Hy", Hz="Hz") + return {"Ex": "Ex", "Ey": "Ey", "Ez": "Ez", "Hx": "Hx", "Hy": "Hy", "Hz": "Hz"} @property - def symmetry_eigenvalues(self) -> Dict[str, Callable[[Axis], float]]: + def symmetry_eigenvalues(self) -> dict[str, Callable[[Axis], float]]: """Maps field components to their (positive) symmetry eigenvalues.""" - return dict( - Ex=lambda dim: -1 if (dim == 0) else +1, - Ey=lambda dim: -1 if (dim == 1) else +1, - Ez=lambda dim: -1 if (dim == 2) else +1, - Hx=lambda dim: +1 if (dim == 0) else -1, - Hy=lambda dim: +1 if (dim == 1) else -1, - Hz=lambda dim: +1 if (dim == 2) else -1, - ) + return { + "Ex": lambda dim: -1 if (dim == 0) else +1, + "Ey": lambda dim: -1 if (dim == 1) else +1, + "Ez": lambda dim: -1 if (dim == 2) else +1, + "Hx": lambda dim: +1 if (dim == 0) else -1, + "Hy": lambda dim: +1 if (dim == 1) else -1, + "Hz": lambda dim: +1 if (dim == 2) else -1, + } class FieldDataset(ElectromagneticFieldDataset): @@ -422,7 +423,7 @@ class AuxFieldDataset(AbstractFieldDataset, ABC): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" fields = { "Nfx": self.Nfx, @@ -432,19 +433,19 @@ def field_components(self) -> Dict[str, DataArray]: return {field_name: field for field_name, field in fields.items() if field is not None} @property - def grid_locations(self) -> Dict[str, str]: + def grid_locations(self) -> dict[str, str]: """Maps field components to the string key of their grid locations on the yee lattice.""" - return dict(Nfx="Ex", Nfy="Ey", Nfz="Ez") + return {"Nfx": "Ex", "Nfy": "Ey", "Nfz": "Ez"} @property - def symmetry_eigenvalues(self) -> Dict[str, Callable[[Axis], float]]: + def symmetry_eigenvalues(self) -> dict[str, Callable[[Axis], float]]: """Maps field components to their (positive) symmetry eigenvalues.""" - return dict( - Nfx=lambda dim: +1, - Nfy=lambda dim: +1, - Nfz=lambda dim: +1, - ) + return { + "Nfx": lambda dim: +1, + "Nfy": lambda dim: +1, + "Nfz": lambda dim: +1, + } class AuxFieldTimeDataset(AuxFieldDataset): @@ -559,7 +560,7 @@ class ModeSolverDataset(ElectromagneticFieldDataset): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" fields = { "Ex": self.Ex, @@ -632,19 +633,19 @@ class PermittivityDataset(AbstractFieldDataset): """ @property - def field_components(self) -> Dict[str, ScalarFieldDataArray]: + def field_components(self) -> dict[str, ScalarFieldDataArray]: """Maps the field components to their associated data.""" - return dict(eps_xx=self.eps_xx, eps_yy=self.eps_yy, eps_zz=self.eps_zz) + return {"eps_xx": self.eps_xx, "eps_yy": self.eps_yy, "eps_zz": self.eps_zz} @property - def grid_locations(self) -> Dict[str, str]: + def grid_locations(self) -> dict[str, str]: """Maps field components to the string key of their grid locations on the yee lattice.""" - return dict(eps_xx="Ex", eps_yy="Ey", eps_zz="Ez") + return {"eps_xx": "Ex", "eps_yy": "Ey", "eps_zz": "Ez"} @property - def symmetry_eigenvalues(self) -> Dict[str, Callable[[Axis], float]]: + def symmetry_eigenvalues(self) -> dict[str, Callable[[Axis], float]]: """Maps field components to their (positive) symmetry eigenvalues.""" - return dict(eps_xx=None, eps_yy=None, eps_zz=None) + return {"eps_xx": None, "eps_yy": None, "eps_zz": None} eps_xx: ScalarFieldDataArray = pd.Field( ..., diff --git a/tidy3d/components/data/monitor_data.py b/tidy3d/components/data/monitor_data.py index 3a20e43d1d..0557f0ec4b 100644 --- a/tidy3d/components/data/monitor_data.py +++ b/tidy3d/components/data/monitor_data.py @@ -6,7 +6,7 @@ import warnings from abc import ABC from math import isclose -from typing import Any, Callable, Dict, List, Optional, Tuple, Union, get_args +from typing import Any, Callable, Literal, Optional, Union, get_args import autograd.numpy as np import pydantic.v1 as pd @@ -14,14 +14,11 @@ from pandas import DataFrame from xarray.core.types import Self -from ...constants import C_0, EPSILON_0, ETA_0, MICROMETER, UnitScaling -from ...exceptions import DataError, SetupError, Tidy3dNotImplementedError, ValidationError -from ...log import log -from ..base import TYPE_TAG_STR, cached_property, skip_if_fields_missing -from ..base_sim.data.monitor_data import AbstractMonitorData -from ..grid.grid import Coords, Grid -from ..medium import Medium, MediumType -from ..monitor import ( +from tidy3d.components.base import TYPE_TAG_STR, cached_property, skip_if_fields_missing +from tidy3d.components.base_sim.data.monitor_data import AbstractMonitorData +from tidy3d.components.grid.grid import Coords, Grid +from tidy3d.components.medium import Medium, MediumType +from tidy3d.components.monitor import ( AuxFieldTimeMonitor, DiffractionMonitor, DirectivityMonitor, @@ -38,27 +35,16 @@ MonitorType, PermittivityMonitor, ) -from ..source.base import Source -from ..source.current import ( - CustomCurrentSource, - PointDipole, -) -from ..source.field import ( - CustomFieldSource, - ModeSource, - PlaneWave, -) -from ..source.time import ( - GaussianPulse, - SourceTimeType, -) -from ..types import ( +from tidy3d.components.source.base import Source +from tidy3d.components.source.current import CustomCurrentSource, PointDipole +from tidy3d.components.source.field import CustomFieldSource, ModeSource, PlaneWave +from tidy3d.components.source.time import GaussianPulse, SourceTimeType +from tidy3d.components.types import ( ArrayFloat1D, ArrayFloat2D, Coordinate, EMField, EpsSpecType, - Literal, Numpy, PolarizationBasis, Size, @@ -66,7 +52,14 @@ TrackFreq, UnitsZBF, ) -from ..validators import enforce_monitor_fields_present, required_if_symmetry_present +from tidy3d.components.validators import ( + enforce_monitor_fields_present, + required_if_symmetry_present, +) +from tidy3d.constants import C_0, EPSILON_0, ETA_0, MICROMETER, UnitScaling +from tidy3d.exceptions import DataError, SetupError, Tidy3dNotImplementedError, ValidationError +from tidy3d.log import log + from .data_array import ( DataArray, DiffractionDataArray, @@ -128,7 +121,7 @@ def normalize(self, source_spectrum_fn: Callable[[float], complex]) -> Dataset: return self.copy() def scale_fields_by_freq_array( - self, freq_array: FreqDataArray, method: str = None + self, freq_array: FreqDataArray, method: Optional[str] = None ) -> MonitorData: """Scale fields in :class:`.MonitorData` by an array of values stored in a :class:`.FreqDataArray`. @@ -152,7 +145,7 @@ def amplitude_fn(freq: list[float]) -> complex: return self.normalize(amplitude_fn) - def _updated(self, update: Dict) -> MonitorData: + def _updated(self, update: dict) -> MonitorData: """Similar to ``updated_copy``, but does not actually copy components, for speed. Note @@ -166,7 +159,7 @@ def _updated(self, update: Dict) -> MonitorData: data_dict.update(update) return type(self).parse_obj(data_dict) - def make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[Source]: + def _make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[Source]: """Generate adjoint sources for this ``MonitorData`` instance.""" # TODO: if there's data in the MonitorData, but no adjoint source, then @@ -192,9 +185,9 @@ def get_amplitude(x) -> complex: """Get the complex amplitude out of some data.""" if isinstance(x, DataArray): - x = complex(x.values) + x = x.values - return 1j * complex(x) + return complex(x) class AbstractFieldData(MonitorData, AbstractFieldDataset, ABC): @@ -204,7 +197,7 @@ class AbstractFieldData(MonitorData, AbstractFieldDataset, ABC): FieldMonitor, FieldTimeMonitor, AuxFieldTimeMonitor, PermittivityMonitor, ModeMonitor ] - symmetry: Tuple[Symmetry, Symmetry, Symmetry] = pd.Field( + symmetry: tuple[Symmetry, Symmetry, Symmetry] = pd.Field( (0, 0, 0), title="Symmetry", description="Symmetry eigenvalues of the original simulation in x, y, and z.", @@ -277,7 +270,7 @@ def symmetry_expanded_copy(self) -> AbstractFieldData: return self.copy(update=self._symmetry_update_dict) @property - def _symmetry_update_dict(self) -> Dict: + def _symmetry_update_dict(self) -> dict: """Dictionary of data fields to create data with expanded symmetry.""" update_dict = {} @@ -446,7 +439,7 @@ def _grid_correction_dict(self): } @property - def _tangential_dims(self) -> List[str]: + def _tangential_dims(self) -> list[str]: """For a 2D monitor data, return the names of the tangential dimensions. Raise if cannot confirm that the associated monitor is 2D.""" if len(self.monitor.zero_dims) != 1: @@ -491,7 +484,7 @@ def colocation_centers(self) -> Coords: return Coords(**colocate_centers) @property - def _plane_grid_boundaries(self) -> Tuple[Coords1D, Coords1D]: + def _plane_grid_boundaries(self) -> tuple[Coords1D, Coords1D]: """For a 2D monitor data, return the boundaries of the in-plane grid to be used to compute differential area and to colocate fields if needed.""" if np.any(np.array(self.monitor.interval_space) > 1): @@ -504,7 +497,7 @@ def _plane_grid_boundaries(self) -> Tuple[Coords1D, Coords1D]: return (bounds_dict[dim1], bounds_dict[dim2]) @property - def _plane_grid_centers(self) -> Tuple[Coords1D, Coords1D]: + def _plane_grid_centers(self) -> tuple[Coords1D, Coords1D]: """For 2D monitor data, return the centers of the in-plane grid""" return [(bs[1:] + bs[:-1]) / 2 for bs in self._plane_grid_boundaries] @@ -522,8 +515,8 @@ def _diff_area(self) -> DataArray: # Append the first and last boundary _, plane_inds = self.monitor.pop_axis([0, 1, 2], self.monitor.size.index(0.0)) - coords[0] = np.array([bounds[0][0]] + coords[0].tolist() + [bounds[0][-1]]) - coords[1] = np.array([bounds[1][0]] + coords[1].tolist() + [bounds[1][-1]]) + coords[0] = np.array([bounds[0][0], *coords[0].tolist(), bounds[0][-1]]) + coords[1] = np.array([bounds[1][0], *coords[1].tolist(), bounds[1][-1]]) """Truncate coords to monitor boundaries. This implicitly makes extra pixels which may be present have size 0 and so won't be included in the integration. For pixels intersected @@ -548,7 +541,7 @@ def _diff_area(self) -> DataArray: return DataArray(np.outer(sizes_dim0, sizes_dim1), dims=self._tangential_dims) - def _tangential_corrected(self, fields: Dict[str, DataArray]) -> Dict[str, DataArray]: + def _tangential_corrected(self, fields: dict[str, DataArray]) -> dict[str, DataArray]: """For a 2D monitor data, extract the tangential components from fields and orient them such that the third component would be the normal axis. This just means that the H field gets an extra minus sign if the normal axis is ``"y"``. Raise if any of the tangential @@ -591,7 +584,7 @@ def _tangential_corrected(self, fields: Dict[str, DataArray]) -> Dict[str, DataA return tan_fields @property - def _tangential_fields(self) -> Dict[str, DataArray]: + def _tangential_fields(self) -> dict[str, DataArray]: """For a 2D monitor data, get the tangential E and H fields in the 2D plane grid. Fields are oriented such that the third component would be the normal axis. This just means that the H field gets an extra minus sign if the normal axis is ``"y"``. @@ -603,7 +596,7 @@ def _tangential_fields(self) -> Dict[str, DataArray]: return self._tangential_corrected(self.symmetry_expanded.field_components) @property - def _colocated_fields(self) -> Dict[str, DataArray]: + def _colocated_fields(self) -> dict[str, DataArray]: """For a 2D monitor data, get all E and H fields colocated to the cell boundaries in the 2D plane grid, with symmetries expanded. """ @@ -623,7 +616,7 @@ def _colocated_fields(self) -> Dict[str, DataArray]: return colocated_fields @property - def _colocated_tangential_fields(self) -> Dict[str, DataArray]: + def _colocated_tangential_fields(self) -> dict[str, DataArray]: """For a 2D monitor data, get the tangential E and H fields colocated to the cell boundaries in the 2D plane grid. Fields are oriented such that the third component would be the normal axis. This just means that the H field gets an extra minus sign if the normal axis is @@ -667,7 +660,7 @@ def intensity(self) -> ScalarFieldDataArray: return intensity.squeeze(dim=normal_dim, drop=True) @property - def poynting(self) -> ScalarFieldDataArray: + def complex_poynting(self) -> ScalarFieldDataArray: """Time-averaged Poynting vector for frequency-domain data associated to a 2D monitor, projected to the direction normal to the monitor plane.""" @@ -684,27 +677,36 @@ def poynting(self) -> ScalarFieldDataArray: e2_h1 = e2 * h1.conj() e_x_h_star = e1_h2 - e2_h1 - poynting = 0.5 * np.real(e_x_h_star) + return 0.5 * e_x_h_star - return poynting + @property + def poynting(self) -> ScalarFieldDataArray: + """Time-averaged Poynting vector for frequency-domain data associated to a 2D monitor, + projected to the direction normal to the monitor plane.""" + return self.complex_poynting.real def package_flux_results(self, flux_values: DataArray) -> Any: """How to package flux""" return FluxDataArray(flux_values) @cached_property - def flux(self) -> FluxDataArray: + def complex_flux(self) -> FluxDataArray: """Flux for data corresponding to a 2D monitor.""" # Compute flux by integrating Poynting vector in-plane d_area = self._diff_area - poynting = self.poynting + poynting = self.complex_poynting flux_values = poynting * d_area flux_values = flux_values.sum(dim=d_area.dims) return self.package_flux_results(flux_values) + @cached_property + def flux(self) -> FluxDataArray: + """Flux for data corresponding to a 2D monitor.""" + return self.complex_flux.real + @cached_property def mode_area(self) -> FreqModeDataArray: r"""Effective mode area corresponding to a 2D monitor. @@ -786,7 +788,7 @@ def dot( return ModeAmpsDataArray(0.25 * integrand.sum(dim=d_area.dims)) - def _interpolated_tangential_fields(self, coords: ArrayFloat2D) -> Dict[str, DataArray]: + def _interpolated_tangential_fields(self, coords: ArrayFloat2D) -> dict[str, DataArray]: """For 2D monitors, interpolate this fields to given coords in the tangential plane. Parameters @@ -942,11 +944,11 @@ def fn(fields_1, fields_2): @staticmethod def _outer_fn_summation( - fields_1: Dict[str, xr.DataArray], - fields_2: Dict[str, xr.DataArray], + fields_1: dict[str, xr.DataArray], + fields_2: dict[str, xr.DataArray], outer_dim_1: str, outer_dim_2: str, - sum_dims: List[str], + sum_dims: list[str], fn: Callable, ) -> DataArray: """ @@ -1083,7 +1085,7 @@ def to_zbf( z_y: float = 0, rec_efficiency: float = 0, sys_efficiency: float = 0, - ) -> Tuple[ScalarFieldDataArray, ScalarFieldDataArray]: + ) -> tuple[ScalarFieldDataArray, ScalarFieldDataArray]: """For a 2D monitor, export the fields to a Zemax Beam File (``.zbf``). The mode area is used to approximate the beam waist, which is only valid @@ -1153,6 +1155,13 @@ def to_zbf( "'freq' was not specified for 'FieldData.to_zbf()'. Defaulting to the mean frequency of the dataset." ) freq = np.mean(e_x.coords["f"].values) + else: + freq = np.array(freq) + + if freq.size > 1: + raise ValueError("'freq' must be a single value, not an array.") + else: + freq = freq.item() mode_area = mode_area.interp(f=freq) e_x = e_x.interp(f=freq) @@ -1235,7 +1244,7 @@ def to_zbf( e_flat = e.values.flatten(order="C") # Interweave real and imaginary parts e_values = np.ravel(np.column_stack((e_flat.real, e_flat.imag))) - fout.write(struct.pack(f"<{2 * n_x*n_y}d", *e_values)) + fout.write(struct.pack(f"<{2 * n_x * n_y}d", *e_values)) return e_x, e_y @@ -1333,9 +1342,9 @@ def to_source( field_dataset=dataset, source_time=source_time, center=center, size=size, **kwargs ) - def make_adjoint_sources( + def _make_adjoint_sources( self, dataset_names: list[str], fwidth: float - ) -> List[CustomCurrentSource]: + ) -> list[CustomCurrentSource]: """Converts a :class:`.FieldData` to a list of adjoint current or point sources.""" sources = [] @@ -1349,6 +1358,12 @@ def make_adjoint_sources( field_component = field_component.sel(f=freq0) values = 2 * -1j * field_component.values + # accounts for the effective size of the source when injecting into a + # simulation with symmetry + symmetry_factor = np.prod(values.shape) / np.prod( + self.symmetry_expanded_copy.field_components[name].sel(f=freq0).values.shape + ) + # make source go backwards if "H" in name: values *= -1 @@ -1370,7 +1385,8 @@ def make_adjoint_sources( omega0 = 2 * np.pi * freq0 scaling_factor = 0.5 * omega0 * EPSILON_0 / size_element - values *= scaling_factor + values *= scaling_factor * symmetry_factor + values = np.nan_to_num(values, nan=0.0) # ignore zero components if not np.all(values == 0): @@ -1584,7 +1600,7 @@ class ModeData(ModeSolverDataset, ElectromagneticFieldData): ..., title="Amplitudes", description="Complex-valued amplitudes associated with the mode." ) - eps_spec: List[EpsSpecType] = pd.Field( + eps_spec: list[EpsSpecType] = pd.Field( None, title="Permettivity Specification", description="Characterization of the permittivity profile on the plane where modes are " @@ -1607,7 +1623,7 @@ def normalize(self, source_spectrum_fn) -> ModeData: """Return copy of self after normalization is applied using source spectrum function.""" source_freq_amps = source_spectrum_fn(self.amps.f)[None, :, None] new_amps = (self.amps / source_freq_amps).astype(self.amps.dtype) - return self.copy(update=dict(amps=new_amps)) + return self.copy(update={"amps": new_amps}) def overlap_sort( self, @@ -1726,7 +1742,7 @@ def _find_ordering_one_freq( self, data_to_sort: ModeData, overlap_thresh: float, - ) -> Tuple[Numpy, Numpy]: + ) -> tuple[Numpy, Numpy]: """Find new ordering of modes in data_to_sort based on their similarity to own modes.""" num_modes = self.n_complex.sizes["mode_index"] @@ -1763,7 +1779,7 @@ def _find_ordering_one_freq( return pairs, complex_amps @staticmethod - def _find_closest_pairs(arr: Numpy) -> Tuple[Numpy, Numpy]: + def _find_closest_pairs(arr: Numpy) -> tuple[Numpy, Numpy]: """Given a complex overlap matrix pair row and column entries.""" n, k = np.shape(arr) @@ -1820,8 +1836,8 @@ def _reorder_modes( ] # Update mode_spec in the monitor - mode_spec = self.monitor.mode_spec.copy(update=dict(track_freq=track_freq)) - update_dict["monitor"] = self.monitor.copy(update=dict(mode_spec=mode_spec)) + mode_spec = self.monitor.mode_spec.copy(update={"track_freq": track_freq}) + update_dict["monitor"] = self.monitor.copy(update={"mode_spec": mode_spec}) return self.copy(update=update_dict) @@ -1927,7 +1943,7 @@ def _colocated_propagation_axes_field(self, field_name: Literal["E", "H"]) -> Da # fields as a (3, ...) numpy array ordered as [tangential1, tagential2, normal] field = [fields[field_name + dim].values for dim in tan_dims] - field = np.array(field + [fields[field_name + normal_dim].values]) + field = np.array([*field, fields[field_name + normal_dim].values]) # rotate axes if mode_spec.angle_phi != 0: @@ -2068,14 +2084,14 @@ def _check_fields_stored(self, components: list[EMField]): "include the mode field profiles in the corresponding 'ModeData'." ) - def make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[ModeSource]: + def _make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[ModeSource]: """Get all adjoint sources for the ``ModeMonitorData``.""" adjoint_sources = [] for name in dataset_names: if name == "amps": - adjoint_sources += self.make_adjoint_sources_amps(fwidth=fwidth) + adjoint_sources += self._make_adjoint_sources_amps(fwidth=fwidth) elif not np.all(self.n_complex.values == 0.0): log.warning( f"Can't create adjoint source for 'ModeData.{type(self)}.{name}'. " @@ -2086,7 +2102,7 @@ def make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[ return adjoint_sources - def make_adjoint_sources_amps(self, fwidth: float) -> list[ModeSource]: + def _make_adjoint_sources_amps(self, fwidth: float) -> list[ModeSource]: """Generate adjoint sources for ``ModeMonitorData.amps``.""" coords = self.amps.coords @@ -2099,15 +2115,15 @@ def make_adjoint_sources_amps(self, fwidth: float) -> list[ModeSource]: for mode_index in coords["mode_index"]: amp_single = self.amps.sel(f=freq, direction=direction, mode_index=mode_index) - if self.get_amplitude(amp_single) == 0.0: + if abs(self.get_amplitude(amp_single)) == 0.0: continue - adjoint_source = self.adjoint_source_amp(amp=amp_single, fwidth=fwidth) + adjoint_source = self._adjoint_source_amp(amp=amp_single, fwidth=fwidth) adjoint_sources.append(adjoint_source) return adjoint_sources - def adjoint_source_amp(self, amp: DataArray, fwidth: float) -> ModeSource: + def _adjoint_source_amp(self, amp: DataArray, fwidth: float) -> ModeSource: """Generate an adjoint ``ModeSource`` for a single amplitude.""" monitor = self.monitor @@ -2122,7 +2138,7 @@ def adjoint_source_amp(self, amp: DataArray, fwidth: float) -> ModeSource: amp_complex = self.get_amplitude(amp) k0 = 2 * np.pi * freq0 / C_0 grad_const = k0 / 4 / ETA_0 - src_amp = grad_const * amp_complex + src_amp = 1j * grad_const * amp_complex # construct source src_adj = ModeSource( @@ -2266,9 +2282,9 @@ class FluxData(MonitorData): ..., title="Flux", description="Flux values in the frequency-domain." ) - def make_adjoint_sources( + def _make_adjoint_sources( self, dataset_names: list[str], fwidth: float - ) -> List[Union[CustomCurrentSource, PointDipole]]: + ) -> list[Union[CustomCurrentSource, PointDipole]]: """Converts a :class:`.FieldData` to a list of adjoint current or point sources.""" # avoids error in edge case where there are extraneous flux monitors not used in objective @@ -2289,7 +2305,7 @@ def normalize(self, source_spectrum_fn) -> FluxData: source_freq_amps = source_spectrum_fn(self.flux.f) source_power = abs(source_freq_amps) ** 2 new_flux = (self.flux / source_power).astype(self.flux.dtype) - return self.copy(update=dict(flux=new_flux)) + return self.copy(update={"flux": new_flux}) class FluxTimeData(MonitorData): @@ -2392,16 +2408,16 @@ class AbstractFieldProjectionData(MonitorData): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" - return dict( - Er=self.Er, - Etheta=self.Etheta, - Ephi=self.Ephi, - Hr=self.Hr, - Htheta=self.Htheta, - Hphi=self.Hphi, - ) + return { + "Er": self.Er, + "Etheta": self.Etheta, + "Ephi": self.Ephi, + "Hr": self.Hr, + "Htheta": self.Htheta, + "Hphi": self.Hphi, + } @property def f(self) -> np.ndarray: @@ -2409,12 +2425,12 @@ def f(self) -> np.ndarray: return np.array(self.Etheta.coords["f"]) @property - def coords(self) -> Dict[str, np.ndarray]: + def coords(self) -> dict[str, np.ndarray]: """Coordinates of the fields contained.""" return self.Etheta.coords @property - def coords_spherical(self) -> Dict[str, np.ndarray]: + def coords_spherical(self) -> dict[str, np.ndarray]: """Coordinates grid for the fields in the spherical system.""" if "theta" in self.coords.keys(): r, theta, phi = np.meshgrid( @@ -2442,7 +2458,7 @@ def coords_spherical(self) -> Dict[str, np.ndarray]: return {"r": r, "theta": theta, "phi": phi} @property - def dims(self) -> Tuple[str, ...]: + def dims(self) -> tuple[str, ...]: """Dimensions of the radiation vectors contained.""" return self.Etheta.dims @@ -2450,7 +2466,7 @@ def make_data_array(self, data: np.ndarray) -> DataArray: """Make an DataArray with data and same coords and dims as fields of self.""" return DataArray(data=data, coords=self.coords, dims=self.dims) - def make_dataset(self, keys: Tuple[str, ...], vals: Tuple[np.ndarray, ...]) -> xr.Dataset: + def make_dataset(self, keys: tuple[str, ...], vals: tuple[np.ndarray, ...]) -> xr.Dataset: """Make an xr.Dataset with keys and data with same coords and dims as fields.""" data_arrays = tuple(map(self.make_data_array, vals)) return xr.Dataset(dict(zip(keys, data_arrays))) @@ -2484,7 +2500,7 @@ def wavenumber(medium: MediumType, frequency: float) -> complex: return (2 * np.pi * frequency / C_0) * (index_n + 1j * index_k) @property - def nk(self) -> Tuple[float, float]: + def nk(self) -> tuple[float, float]: """Returns the real and imaginary parts of the background medium's refractive index.""" return self.medium.nk_model(frequency=self.f) @@ -2606,9 +2622,9 @@ def radar_cross_section(self) -> DataArray: return self.make_data_array(data=rcs_data) - def make_adjoint_sources( + def _make_adjoint_sources( self, dataset_names: list[str], fwidth: float - ) -> List[Union[CustomCurrentSource, PointDipole]]: + ) -> list[Union[CustomCurrentSource, PointDipole]]: """Error if server-side field projection is used for autograd""" raise NotImplementedError( @@ -2650,7 +2666,7 @@ class FieldProjectionAngleData(AbstractFieldProjectionData): description="Field projection monitor with an angle-based projection grid.", ) - projection_surfaces: Tuple[FieldProjectionSurface, ...] = pd.Field( + projection_surfaces: tuple[FieldProjectionSurface, ...] = pd.Field( ..., title="Projection surfaces", description="Surfaces of the monitor where near fields were recorded for projection", @@ -2764,7 +2780,7 @@ def _check_integration_suitability(self): "There are not enough sampling points along `theta` or `phi` for accurate integration. " f"Currently, {len(self.theta)} samples for `theta` and {len(self.phi)} samples for `phi`. " f"Consider using, at the very least, {MIN_ANGULAR_SAMPLES_SPHERE} samples for `theta` and " - f"{2*MIN_ANGULAR_SAMPLES_SPHERE} samples for `phi`." + f"{2 * MIN_ANGULAR_SAMPLES_SPHERE} samples for `phi`." ) self._check_coords_sorted(self.theta, "theta") self._check_coords_sorted(self.phi, "phi") @@ -2860,7 +2876,7 @@ class FieldProjectionCartesianData(AbstractFieldProjectionData): description="Field projection monitor with a Cartesian projection grid.", ) - projection_surfaces: Tuple[FieldProjectionSurface, ...] = pd.Field( + projection_surfaces: tuple[FieldProjectionSurface, ...] = pd.Field( ..., title="Projection surfaces", description="Surfaces of the monitor where near fields were recorded for projection", @@ -3013,7 +3029,7 @@ class FieldProjectionKSpaceData(AbstractFieldProjectionData): description="Field projection monitor with a projection grid defined in k-space.", ) - projection_surfaces: Tuple[FieldProjectionSurface, ...] = pd.Field( + projection_surfaces: tuple[FieldProjectionSurface, ...] = pd.Field( ..., title="Projection surfaces", description="Surfaces of the monitor where near fields were recorded for projection", @@ -3171,14 +3187,14 @@ class DiffractionData(AbstractFieldProjectionData): description="Spatial distribution of phi-component of the magnetic field.", ) - sim_size: Tuple[float, float] = pd.Field( + sim_size: tuple[float, float] = pd.Field( ..., title="Domain size", description="Size of the near field in the local x and y directions.", units=MICROMETER, ) - bloch_vecs: Union[Tuple[float, float], Tuple[ArrayFloat1D, ArrayFloat1D]] = pd.Field( + bloch_vecs: Union[tuple[float, float], tuple[ArrayFloat1D, ArrayFloat1D]] = pd.Field( ..., title="Bloch vectors", description="Bloch vectors along the local x and y directions in units of " @@ -3186,7 +3202,7 @@ class DiffractionData(AbstractFieldProjectionData): ) @staticmethod - def shifted_orders(orders: Tuple[int, ...], bloch_vec: Union[float, np.ndarray]) -> np.ndarray: + def shifted_orders(orders: tuple[int, ...], bloch_vec: Union[float, np.ndarray]) -> np.ndarray: """Diffraction orders shifted by the Bloch vector.""" return bloch_vec + np.atleast_2d(orders).T @@ -3207,8 +3223,8 @@ def reciprocal_coords( @staticmethod def compute_angles( - reciprocal_vectors: Tuple[np.ndarray, np.ndarray], - ) -> Tuple[np.ndarray, np.ndarray]: + reciprocal_vectors: tuple[np.ndarray, np.ndarray], + ) -> tuple[np.ndarray, np.ndarray]: """Compute the polar and azimuth angles associated with the given reciprocal vectors.""" # some wave number pairs are outside the light cone, leading to warnings from numpy.arcsin with warnings.catch_warnings(): @@ -3220,7 +3236,7 @@ def compute_angles( return (thetas, phis) @property - def coords_spherical(self) -> Dict[str, np.ndarray]: + def coords_spherical(self) -> dict[str, np.ndarray]: """Coordinates grid for the fields in the spherical system.""" theta, phi = self.angles return {"r": None, "theta": theta, "phi": phi} @@ -3236,7 +3252,7 @@ def orders_y(self) -> np.ndarray: return np.atleast_1d(np.array(self.Etheta.coords["orders_y"])) @property - def reciprocal_vectors(self) -> Tuple[np.ndarray, np.ndarray]: + def reciprocal_vectors(self) -> tuple[np.ndarray, np.ndarray]: """Get the normalized "ux" and "uy" reciprocal vectors.""" return (self.ux, self.uy) @@ -3267,7 +3283,7 @@ def uy(self) -> np.ndarray: ) @property - def angles(self) -> Tuple[DataArray]: + def angles(self) -> tuple[DataArray]: """The (theta, phi) angles corresponding to each allowed pair of diffraction orders storeds as data arrays. Disallowed angles are set to ``np.nan``. """ @@ -3350,7 +3366,7 @@ def fields_cartesian(self) -> xr.Dataset: keys = ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"] return self._make_dataset(fields, keys) - def _make_dataset(self, fields: Tuple[np.ndarray, ...], keys: Tuple[str, ...]) -> xr.Dataset: + def _make_dataset(self, fields: tuple[np.ndarray, ...], keys: tuple[str, ...]) -> xr.Dataset: """Make an xr.Dataset for fields with given field names.""" data_arrays = [] for field in fields: @@ -3359,13 +3375,13 @@ def _make_dataset(self, fields: Tuple[np.ndarray, ...], keys: Tuple[str, ...]) - """ Autograd code """ - def make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[PlaneWave]: + def _make_adjoint_sources(self, dataset_names: list[str], fwidth: float) -> list[PlaneWave]: """Get all adjoint sources for the ``DiffractionMonitor.amps``.""" # NOTE: everything just goes through `.amps`, any post-processing is encoded in E-fields - return self.make_adjoint_sources_amps(fwidth=fwidth) + return self._make_adjoint_sources_amps(fwidth=fwidth) - def make_adjoint_sources_amps(self, fwidth: float) -> list[PlaneWave]: + def _make_adjoint_sources_amps(self, fwidth: float) -> list[PlaneWave]: """Make adjoint sources for outputs that depend on DiffractionData.`amps`.""" amps = self.amps @@ -3388,7 +3404,7 @@ def make_adjoint_sources_amps(self, fwidth: float) -> list[PlaneWave]: # ignore any amplitudes of 0.0 or nan amp_complex = self.get_amplitude(amp_single) - if (amp_complex == 0.0) or np.isnan(amp_complex): + if (abs(amp_complex) == 0.0) or np.isnan(amp_complex): continue # compute a plane wave for this amplitude (if propagating / not None) @@ -3412,7 +3428,7 @@ def adjoint_source_amp(self, amp: DataArray, fwidth: float) -> PlaneWave: # compute the angle corresponding to this amplitude theta_data, phi_data = self.angles - angle_sel_kwargs = dict(orders_x=int(order_x), orders_y=int(order_y), f=float(freq0)) + angle_sel_kwargs = {"orders_x": int(order_x), "orders_y": int(order_y), "f": float(freq0)} angle_theta = float(theta_data.sel(**angle_sel_kwargs)) angle_phi = float(phi_data.sel(**angle_sel_kwargs)) @@ -3508,7 +3524,7 @@ def from_spherical_field_dataset( New :class:`.DirectivityData` instance with computed flux from spherical field integration. """ f = list(monitor.freqs) - flux = FluxDataArray(np.zeros(len(f)), coords=dict(f=f)) + flux = FluxDataArray(np.zeros(len(f)), coords={"f": f}) dir_data = DirectivityData( monitor=monitor, flux=flux, @@ -3563,7 +3579,7 @@ def _check_valid_pol_basis(pol_basis: PolarizationBasis, tilt_angle: float): raise ValueError("'tilt_angle' is only defined for linear polarization.") def partial_radiation_intensity( - self, pol_basis: PolarizationBasis = "linear", tilt_angle: float = None + self, pol_basis: PolarizationBasis = "linear", tilt_angle: Optional[float] = None ) -> xr.Dataset: """Partial radiation intensity in the frequency domain as a function of angles theta and phi. The partial radiation intensities are computed in the ``linear`` or ``circular`` polarization @@ -3635,13 +3651,13 @@ def radiated_power(self) -> FreqDataArray: isinstance(self.monitor, FieldProjectionAngleMonitor) or self.monitor.size.count(0.0) == 0 ): - return FreqDataArray(self.flux.values, dict(f=self.f)) + return FreqDataArray(self.flux.values, {"f": self.f}) # The monitor could be planar and directed downward sign = 1.0 if self.monitor.normal_dir == "+" else -1.0 - return FreqDataArray(sign * self.flux.values, dict(f=self.f)) + return FreqDataArray(sign * self.flux.values, {"f": self.f}) def partial_directivity( - self, pol_basis: PolarizationBasis = "linear", tilt_angle: float = None + self, pol_basis: PolarizationBasis = "linear", tilt_angle: Optional[float] = None ) -> xr.Dataset: """Directivity in the frequency domain as a function of angles theta and phi. The partial directivities are computed in the ``linear`` or ``circular`` polarization @@ -3704,13 +3720,13 @@ def calc_radiation_efficiency(self, power_in: FreqDataArray) -> FreqDataArray: Radiation efficiency (dimensionless) in the frequency domain, computed as radiated_power / power_in. """ - return FreqDataArray((self.radiated_power / power_in).values, dict(f=self.f)) + return FreqDataArray((self.radiated_power / power_in).values, {"f": self.f}) def calc_partial_gain( self, power_in: FreqDataArray, pol_basis: PolarizationBasis = "linear", - tilt_angle: float = None, + tilt_angle: Optional[float] = None, ) -> xr.Dataset: """The partial gain figures of merit for antennas. The partial gains are computed in the ``linear`` or ``circular`` polarization bases. If ``tilt_angle`` is not ``None``, diff --git a/tidy3d/components/data/sim_data.py b/tidy3d/components/data/sim_data.py index 4e63e3f5ab..55de11ecaf 100644 --- a/tidy3d/components/data/sim_data.py +++ b/tidy3d/components/data/sim_data.py @@ -6,34 +6,31 @@ import pathlib from abc import ABC from collections import defaultdict -from typing import Callable, Tuple, Union +from typing import Callable, Optional, Union import h5py import numpy as np import pydantic.v1 as pd import xarray as xr -from ...constants import C_0, inf -from ...exceptions import DataError, FileError, Tidy3dKeyError -from ...log import log -from ..autograd.utils import split_list -from ..base import JSON_TAG, Tidy3dBaseModel -from ..base_sim.data.sim_data import AbstractSimulationData -from ..file_util import replace_values -from ..monitor import Monitor -from ..simulation import Simulation -from ..source.time import GaussianPulse -from ..source.utils import SourceType -from ..structure import Structure -from ..types import Ax, Axis, ColormapType, FieldVal, PlotScale, annotate_type -from ..viz import add_ax_if_none, equal_aspect +from tidy3d.components.autograd.utils import split_list +from tidy3d.components.base import JSON_TAG, Tidy3dBaseModel +from tidy3d.components.base_sim.data.sim_data import AbstractSimulationData +from tidy3d.components.file_util import replace_values +from tidy3d.components.monitor import Monitor +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.current import CustomCurrentSource +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.source.utils import SourceType +from tidy3d.components.structure import Structure +from tidy3d.components.types import Ax, Axis, ColormapType, FieldVal, PlotScale, annotate_type +from tidy3d.components.viz import add_ax_if_none, equal_aspect +from tidy3d.constants import C_0, inf +from tidy3d.exceptions import DataError, FileError, Tidy3dKeyError +from tidy3d.log import log + from .data_array import FreqDataArray -from .monitor_data import ( - AbstractFieldData, - FieldTimeData, - MonitorDataType, - MonitorDataTypes, -) +from .monitor_data import AbstractFieldData, FieldTimeData, MonitorDataType, MonitorDataTypes DATA_TYPE_MAP = {data.__fields__["monitor"].type_: data for data in MonitorDataTypes} @@ -43,11 +40,17 @@ # residuals below this are considered good fits for broadband adjoint source creation RESIDUAL_CUTOFF_ADJOINT = 1e-6 +# for adjoint source, the minimum number of FWIDTH between the center frequency and zero +NUM_ADJOINT_FWIDTH_TO_ZERO = 3 +# for broadband adjoint source, the minimum number of FWIDTH to reach the lowest frequency +# that is covered by the broadband pulse +NUM_ADJOINT_FWIDTH_TO_FMIN = 0.5 + class AdjointSourceInfo(Tidy3dBaseModel): """Stores information about the adjoint sources to pass to autograd pipeline.""" - sources: Tuple[annotate_type(SourceType), ...] = pd.Field( + sources: tuple[annotate_type(SourceType), ...] = pd.Field( ..., title="Adjoint Sources", description="Set of processed sources to include in the adjoint simulation.", @@ -445,8 +448,8 @@ def plot_field_monitor_data( eps_alpha: float = 0.2, phase: float = 0.0, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, shading: str = "flat", **sel_kwargs, @@ -560,7 +563,7 @@ def plot_field_monitor_data( if field_data.coords[axis].size <= 1: field_data = field_data.sel(**{axis: pos}, method="nearest") else: - field_data = field_data.interp(**{axis: pos}, kwargs=dict(bounds_error=True)) + field_data = field_data.interp(**{axis: pos}, kwargs={"bounds_error": True}) # warn about new API changes and replace the values if "freq" in sel_kwargs: @@ -580,6 +583,9 @@ def plot_field_monitor_data( # select the extra coordinates out of the data from user-specified kwargs for coord_name, coord_val in sel_kwargs.items(): + interp_val = np.array(coord_val) + if interp_val.size == 1: + interp_val = interp_val.item() if ( field_data.coords[coord_name].size <= 1 or coord_name == "eme_port_index" @@ -587,10 +593,10 @@ def plot_field_monitor_data( or coord_name == "sweep_index" or coord_name == "mode_index" ): - field_data = field_data.sel(**{coord_name: coord_val}, method=None) + field_data = field_data.sel(**{coord_name: interp_val}, method=None) else: field_data = field_data.interp( - **{coord_name: coord_val}, kwargs=dict(bounds_error=True) + **{coord_name: interp_val}, kwargs={"bounds_error": True} ) # before dropping coordinates, check if a frequency can be derived from the data that can @@ -656,8 +662,8 @@ def plot_field( eps_alpha: float = 0.2, phase: float = 0.0, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, shading: str = "flat", **sel_kwargs, @@ -734,11 +740,11 @@ def plot_scalar_array( field_data: xr.DataArray, axis: Axis, position: float, - freq: float = None, + freq: Optional[float] = None, eps_alpha: float = 0.2, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, cmap_type: ColormapType = "divergent", ax: Ax = None, **kwargs, @@ -912,7 +918,7 @@ class SimulationData(AbstractYeeGridSimulationData): description="Original :class:`.Simulation` associated with the data.", ) - data: Tuple[annotate_type(MonitorDataType), ...] = pd.Field( + data: tuple[annotate_type(MonitorDataType), ...] = pd.Field( ..., title="Monitor Data", description="List of :class:`.MonitorData` instances " @@ -990,11 +996,11 @@ def source_spectrum_fn(freqs): # Make a new monitor_data dictionary with renormalized data data_normalized = [mnt_data.normalize(source_spectrum_fn) for mnt_data in self.data] - simulation = self.simulation.copy(update=dict(normalize_index=normalize_index)) + simulation = self.simulation.copy(update={"normalize_index": normalize_index}) - return self.copy(update=dict(simulation=simulation, data=data_normalized)) + return self.copy(update={"simulation": simulation, "data": data_normalized}) - def split_adjoint_data(self: SimulationData, num_mnts_original: int) -> tuple[list, list]: + def _split_adjoint_data(self: SimulationData, num_mnts_original: int) -> tuple[list, list]: """Split data list into original, adjoint field, and adjoint permittivity.""" data_all = list(self.data) @@ -1008,11 +1014,11 @@ def split_adjoint_data(self: SimulationData, num_mnts_original: int) -> tuple[li return data_original, data_adjoint - def split_original_fwd(self, num_mnts_original: int) -> Tuple[SimulationData, SimulationData]: + def _split_original_fwd(self, num_mnts_original: int) -> tuple[SimulationData, SimulationData]: """Split this simulation data into original and fwd data from number of original mnts.""" # split the data and monitors into the original ones & adjoint gradient ones (for 'fwd') - data_original, data_fwd = self.split_adjoint_data(num_mnts_original=num_mnts_original) + data_original, data_fwd = self._split_adjoint_data(num_mnts_original=num_mnts_original) monitors_orig, monitors_fwd = split_list(self.simulation.monitors, index=num_mnts_original) # reconstruct the simulation data for the user, using original sim, and data for original mnts @@ -1033,7 +1039,7 @@ def split_original_fwd(self, num_mnts_original: int) -> Tuple[SimulationData, Si return sim_data_original, sim_data_fwd - def make_adjoint_sims( + def _make_adjoint_sims( self, data_vjp_paths: set[tuple], adjoint_monitors: list[Monitor], @@ -1046,7 +1052,7 @@ def make_adjoint_sims( sim_original = self.simulation # generate the adjoint sources {mnt_name : list[Source]} - sources_adj_dict = self.make_adjoint_sources(data_vjp_paths=data_vjp_paths) + sources_adj_dict = self._make_adjoint_sources(data_vjp_paths=data_vjp_paths) if not sources_adj_dict: return [] @@ -1054,7 +1060,7 @@ def make_adjoint_sims( for src_list in sources_adj_dict.values(): adj_srcs += list(src_list) - adjoint_source_infos = self.process_adjoint_sources(adj_srcs=adj_srcs) + adjoint_source_infos = self._process_adjoint_sources(adj_srcs=adj_srcs) if not adjoint_source_infos: return [] @@ -1076,12 +1082,12 @@ def make_adjoint_sims( ] # fields to update the 'fwd' simulation with to make it 'adj' - sim_adj_update_dict = dict( - sources=adjoint_source_info.sources, - boundary_spec=bc_adj, - monitors=monitors, - post_norm=adjoint_source_info.post_norm, - ) + sim_adj_update_dict = { + "sources": adjoint_source_info.sources, + "boundary_spec": bc_adj, + "monitors": monitors, + "post_norm": adjoint_source_info.post_norm, + } if not adjoint_source_info.normalize_sim: sim_adj_update_dict["normalize_index"] = None @@ -1095,7 +1101,7 @@ def make_adjoint_sims( return adj_sims - def make_adjoint_sources(self, data_vjp_paths: set[tuple]) -> dict[str, SourceType]: + def _make_adjoint_sources(self, data_vjp_paths: set[tuple]) -> dict[str, SourceType]: """Generate all of the non-zero sources for the adjoint simulation given the VJP data.""" # map of index into 'self.data' to the list of datasets we need adjoint sources for @@ -1107,8 +1113,8 @@ def make_adjoint_sources(self, data_vjp_paths: set[tuple]) -> dict[str, SourceTy sources_adj_all = defaultdict(list) for data_index, dataset_names in adj_src_map.items(): mnt_data = self.data[data_index] - sources_adj = mnt_data.make_adjoint_sources( - dataset_names=dataset_names, fwidth=self.fwidth_adj + sources_adj = mnt_data._make_adjoint_sources( + dataset_names=dataset_names, fwidth=self._fwidth_adj ) sources_adj_all[mnt_data.monitor.name] = sources_adj log.info( @@ -1118,19 +1124,37 @@ def make_adjoint_sources(self, data_vjp_paths: set[tuple]) -> dict[str, SourceTy return sources_adj_all @property - def fwidth_adj(self) -> float: + def _fwidth_adj(self) -> float: # fwidth of forward pass, try as default for adjoint normalize_index_fwd = self.simulation.normalize_index or 0 return self.simulation.sources[normalize_index_fwd].source_time.fwidth - def process_adjoint_sources(self, adj_srcs: list[SourceType]) -> list[AdjointSourceInfo]: + @staticmethod + def _adjoint_src_width_single(adj_srcs: list[SourceType]) -> list[SourceType]: + """Ensure the adjoint source sufficiently decays before zero frequency.""" + adj_srcs_process_fwidth = [] + for adj_src in adj_srcs: + source_time = adj_src.source_time + freq0 = source_time.freq0 + + fwidth = np.minimum(freq0 / NUM_ADJOINT_FWIDTH_TO_ZERO, source_time.fwidth) + + adj_srcs_process_fwidth.append( + adj_src.updated_copy(source_time=source_time.updated_copy(fwidth=fwidth)) + ) + + return adj_srcs_process_fwidth + + def _process_adjoint_sources(self, adj_srcs: list[SourceType]) -> list[AdjointSourceInfo]: """Compute list of final sources along with a post run normalization for adj fields.""" # dictionary mapping hash of sources with same freq dependence to list of time-dependencies hashes_to_sources = defaultdict(None) hashes_to_src_times = defaultdict(list) + adj_srcs_process_fwidth = self._adjoint_src_width_single(adj_srcs) + tmp_src_time = GaussianPulse(freq0=C_0, fwidth=inf) - for src in adj_srcs: + for src in adj_srcs_process_fwidth: tmp_src = src.updated_copy(source_time=tmp_src_time) tmp_src_hash = tmp_src._hash_self() hashes_to_sources[tmp_src_hash] = src @@ -1138,26 +1162,39 @@ def process_adjoint_sources(self, adj_srcs: list[SourceType]) -> list[AdjointSou # Group sources by frequency or port, whichever gives fewer groups num_ports = len(hashes_to_src_times) - num_unique_freqs = len({src.source_time.freq0 for src in adj_srcs}) + num_unique_freqs = len({src.source_time.freq0 for src in adj_srcs_process_fwidth}) log.info(f"Found {num_ports} spatial ports and {num_unique_freqs} unique frequencies.") adjoint_infos = [] if num_unique_freqs <= num_ports: log.info("Grouping adjoint sources by frequency.") - unique_freqs = {src.source_time.freq0 for src in adj_srcs} + unique_freqs = {src.source_time.freq0 for src in adj_srcs_process_fwidth} for freq0 in unique_freqs: - group = [src for src in adj_srcs if src.source_time.freq0 == freq0] + group = [src for src in adj_srcs_process_fwidth if src.source_time.freq0 == freq0] post_norm = xr.DataArray(data=np.array([1 + 0j]), coords={"f": [freq0]}) adjoint_infos.append( AdjointSourceInfo(sources=group, post_norm=post_norm, normalize_sim=True) ) else: log.info("Grouping adjoint sources by port.") + + # + # warn if the forward simulation had symmetry and we are grouping by port, which + # which means the individual adjoint simulations may not respect the original symmetry + # + if np.any(np.abs(self.simulation.symmetry) > 0): + log.warning( + "The adjoint simulations for this problem are being broken into " + "multiple simulations that may not individually respect the symmetry of the " + "initial simulation. Gradients may be unreliable and it is recommended to " + "optimize this problem without utilizing symmetry." + ) + for src_hash, src_times in hashes_to_src_times.items(): base_src = hashes_to_sources[src_hash] group = [base_src.updated_copy(source_time=src_time) for src_time in src_times] - processed_srcs, post_norm = self.process_adjoint_sources_broadband(group) + processed_srcs, post_norm = self._process_adjoint_sources_broadband(group) adjoint_infos.append( AdjointSourceInfo( sources=processed_srcs, post_norm=post_norm, normalize_sim=True @@ -1167,7 +1204,7 @@ def process_adjoint_sources(self, adj_srcs: list[SourceType]) -> list[AdjointSou log.info(f"Created {len(adjoint_infos)} adjoint source groups.") return adjoint_infos - def process_adjoint_sources_broadband( + def _process_adjoint_sources_broadband( self, adj_srcs: list[SourceType] ) -> tuple[list[SourceType], xr.DataArray]: """Process adjoint sources for the case of several sources at the same freq.""" @@ -1184,12 +1221,46 @@ def process_adjoint_sources_broadband( return [src_broadband], post_norm_amps + @staticmethod + def _adjoint_src_width_broadband(adj_srcs: list[SourceType]) -> float: + """Find the adjoint source fwidth that sufficiently covers all adjoint frequencies.""" + + adj_srcs_f0 = [adj_src.source_time.freq0 for adj_src in adj_srcs] + middle_f0 = 0.5 * (np.max(adj_srcs_f0) + np.min(adj_srcs_f0)) + min_f0 = np.min(adj_srcs_f0) + + # width of source to sufficiently decay by zero frequency + decay_by_f0_fwidth = middle_f0 / NUM_ADJOINT_FWIDTH_TO_ZERO + # width of source to sufficiently cover all adjoint frequencies + fwidth_to_min_f0 = (middle_f0 - min_f0) / NUM_ADJOINT_FWIDTH_TO_FMIN + + # log warning if the adjoint pulse width is not sufficiently decayed by zero frequency + # which may cause some issues in the adjoint accuracy when using field sources + if (fwidth_to_min_f0 > decay_by_f0_fwidth) and isinstance(adj_srcs[0], CustomCurrentSource): + log.warning( + "Adjoint source generated with a frequency spectrum that extends to or overlaps with 0 Hz. " + "This can introduce errors into the gradient computation." + ) + + # Choose a wider pulse width in frequency especially when the min/max frequencies + # for the broadband pulse might be very close together + adj_src_fwidth = np.maximum(decay_by_f0_fwidth, fwidth_to_min_f0) + + return middle_f0, adj_src_fwidth + def _make_broadband_source(self, adj_srcs: list[SourceType]) -> SourceType: """Make a broadband source for a set of adjoint sources.""" + adj_src_f0, adj_src_fwidth = self._adjoint_src_width_broadband(adj_srcs) + source_index = self.simulation.normalize_index or 0 - src_time_base = self.simulation.sources[source_index].source_time.copy() - src_broadband = adj_srcs[0].updated_copy(source_time=src_time_base) + + src_time_base = self.simulation.sources[source_index].source_time.updated_copy( + amplitude=1.0, phase=0.0 + ) + src_broadband = adj_srcs[0].updated_copy( + source_time=src_time_base.updated_copy(freq0=adj_src_f0, fwidth=adj_src_fwidth) + ) return src_broadband @@ -1205,14 +1276,14 @@ def _make_post_norm_amps(adj_srcs: list[SourceType]) -> xr.DataArray: amp_complex = src_time.amplitude * np.exp(1j * src_time.phase) amps_complex.append(amp_complex) - coords = dict(f=freqs) + coords = {"f": freqs} amps_complex = np.array(amps_complex) return xr.DataArray(amps_complex, coords=coords) - def get_adjoint_data(self, structure_index: int, data_type: str) -> MonitorDataType: + def _get_adjoint_data(self, structure_index: int, data_type: str) -> MonitorDataType: """Grab the field or permittivity data for a given structure index.""" - monitor_name = Structure.get_monitor_name(index=structure_index, data_type=data_type) + monitor_name = Structure._get_monitor_name(index=structure_index, data_type=data_type) return self[monitor_name] def to_mat_file(self, fname: str, **kwargs): diff --git a/tidy3d/components/data/unstructured/base.py b/tidy3d/components/data/unstructured/base.py index cd27e32707..b5866fd2d6 100644 --- a/tidy3d/components/data/unstructured/base.py +++ b/tidy3d/components/data/unstructured/base.py @@ -4,7 +4,7 @@ import numbers from abc import ABC, abstractmethod -from typing import Literal, Tuple, Union +from typing import Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -114,21 +114,21 @@ def values_right_indexing(cls, val): ) return val - @pd.validator("values", always=True) - @skip_if_fields_missing(["points"]) - def number_of_values_matches_points(cls, val, values): + @pd.root_validator(skip_on_failure=True) + def number_of_values_matches_points(cls, values): """Check that the number of data values matches the number of grid points.""" - num_values = len(val.index) - points = values.get("points") - num_points = len(points) + vals = values.get("values") - if num_points != num_values: - raise ValidationError( - f"The number of data values ({num_values}) does not match the number of grid " - f"points ({num_points})." - ) - return val + if points is not None and vals is not None: + num_points = len(points) + num_values = len(vals.index) + if num_points != num_values: + raise ValidationError( + f"The number of data values ({num_values}) does not match the number of grid " + f"points ({num_points})." + ) + return values @pd.validator("cells", always=True) def match_cells_to_vtk_type(cls, val): @@ -169,7 +169,7 @@ def check_cell_vertex_range(cls, val, values): raise ValidationError( "Cell connections array uses undefined point indices in the range " f"[{min_index_used}, {max_index_used}]. The valid range of point indices is " - f"[0, {num_points-1}]." + f"[0, {num_points - 1}]." ) return val @@ -312,7 +312,7 @@ def _remove_degenerate_cells(cls, cells: CellDataArray): data = np.delete(cells.values, list(degenerate_cells), axis=0) cell_index = np.delete(cells.cell_index.values, list(degenerate_cells)) return CellDataArray( - data=data, coords=dict(cell_index=cell_index, vertex_index=cells.vertex_index) + data=data, coords={"cell_index": cell_index, "vertex_index": cells.vertex_index} ) return cells @@ -483,17 +483,29 @@ def _read_vtkUnstructuredGrid(fname: str): return grid + @staticmethod + @requires_vtk + def _read_vtkLegacyFile(fname: str): + """Load a grid from a legacy `.vtk` file.""" + reader = vtk["mod"].vtkGenericDataObjectReader() + reader.SetFileName(fname) + reader.Update() + grid = reader.GetOutput() + + return grid + @classmethod @abstractmethod @requires_vtk def _from_vtk_obj( cls, vtk_obj, - field: str = None, + field: Optional[str] = None, remove_degenerate_cells: bool = False, remove_unused_points: bool = False, values_type=IndexedDataArray, expect_complex=None, + ignore_invalid_cells=False, ) -> UnstructuredGridDataset: """Initialize from a vtk object.""" @@ -521,15 +533,16 @@ def _from_vtk_obj_internal( def from_vtu( cls, file: str, - field: str = None, + field: Optional[str] = None, remove_degenerate_cells: bool = False, remove_unused_points: bool = False, + ignore_invalid_cells: bool = False, ) -> UnstructuredGridDataset: """Load unstructured data from a vtu file. Parameters ---------- - fname : str + file : str Full path to the .vtu file to load the unstructured data from. field : str = None Name of the field to load. @@ -537,6 +550,8 @@ def from_vtu( Remove explicitly degenerate cells. remove_unused_points : bool = False Remove unused points. + ignore_invalid_cells : bool = False + Whether to ignore invalid cells during loading. Returns ------- @@ -549,6 +564,46 @@ def from_vtu( field=field, remove_degenerate_cells=remove_degenerate_cells, remove_unused_points=remove_unused_points, + ignore_invalid_cells=ignore_invalid_cells, + ) + + @classmethod + @requires_vtk + def from_vtk( + cls, + file: str, + field: Optional[str] = None, + remove_degenerate_cells: bool = False, + remove_unused_points: bool = False, + ignore_invalid_cells: bool = False, + ) -> UnstructuredGridDataset: + """Load unstructured data from a vtk file. + + Parameters + ---------- + file : str + Full path to the .vtk file to load the unstructured data from. + field : str = None + Name of the field to load. + remove_degenerate_cells : bool = False + Remove explicitly degenerate cells. + remove_unused_points : bool = False + Remove unused points. + remove_invalid_cells : bool = False + Remove invalid cells. + + Returns + ------- + UnstructuredGridDataset + Unstructured data. + """ + grid = cls._read_vtkLegacyFile(file) + return cls._from_vtk_obj( + grid, + field=field, + remove_degenerate_cells=remove_degenerate_cells, + remove_unused_points=remove_unused_points, + ignore_invalid_cells=ignore_invalid_cells, ) @requires_vtk @@ -566,13 +621,27 @@ def to_vtu(self, fname: str): writer.SetInputData(self._vtk_obj) writer.Write() + @classmethod + @requires_vtk + def _cell_to_point_data( + cls, + vtk_obj, + ): + """Get point data values from a VTK object.""" + + cellDataToPointData = vtk["mod"].vtkCellDataToPointData() + cellDataToPointData.SetInputData(vtk_obj) + cellDataToPointData.Update() + + return cellDataToPointData.GetOutput() + @classmethod @requires_vtk def _get_values_from_vtk( cls, vtk_obj, num_points: pd.PositiveInt, - field: str = None, + field: Optional[str] = None, values_type=IndexedDataArray, expect_complex=None, ) -> IndexedDataArray: @@ -586,7 +655,7 @@ def _get_values_from_vtk( "No point data is found in a VTK object. '.values' will be initialized to zeros." ) values_numpy = np.zeros(num_points) - values_coords = {"index": []} + values_coords = {"index": np.arange(num_points)} values_name = None else: @@ -633,7 +702,7 @@ def _get_values_from_vtk( "'.values' while the rest will be ignored." ) - values_coords = dict(index=np.arange(num_points)) + values_coords = {"index": np.arange(num_points)} if isinstance(field, dict): values_coords.update(field) @@ -645,6 +714,14 @@ def get_cell_values(self, **kwargs): """This function returns the cell values for the fields stored in the UnstructuredGridDataset. If multiple fields are stored per point, like in an IndexedVoltageDataArray, cell values will be provided for each of the fields unless a selection argument is provided, e.g., voltage=0.2 + Parameters + ---------- + **kwargs : dict + Keyword arguments to pass to the xarray sel() function. + Returns + ------- + numpy.ndarray + Extracted data. """ values = self.values.sel(**kwargs) @@ -796,8 +873,8 @@ def interp( x: Union[float, ArrayLike] = None, y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, - fill_value: Union[ - float, Literal["extrapolate"] + fill_value: Optional[ + Union[float, Literal["extrapolate"]] ] = None, # TODO: an array if multiple fields? use_vtk: bool = False, method: Literal["linear", "nearest"] = "linear", @@ -909,7 +986,7 @@ def _non_spatial_interp(self, method="linear", fill_value=np.nan, **coords_kwarg values=self.values.interp( **coords_kwargs_only_lists, method="linear", - kwargs=dict(fill_value=fill_value), + kwargs={"fill_value": fill_value}, ) ) @@ -918,8 +995,8 @@ def _spatial_interp( x: Union[float, ArrayLike], y: Union[float, ArrayLike], z: Union[float, ArrayLike], - fill_value: Union[ - float, Literal["extrapolate"] + fill_value: Optional[ + Union[float, Literal["extrapolate"]] ] = None, # TODO: an array if multiple fields? use_vtk: bool = False, method: Literal["linear", "nearest"] = "linear", @@ -1001,7 +1078,7 @@ def _spatial_interp( interpolated_values, x=x, y=y, z=z ) - coords_dict = dict(x=x, y=y, z=z) + coords_dict = {"x": x, "y": y, "z": z} coords_dict.update(self._values_coords_dict) if len(self._values_coords_dict) == 0: @@ -1370,7 +1447,7 @@ def _interp_py_general( # in case of 2d grid broadcast results along normal direction assuming translational # invariance if num_dims == 2: - orig_shape = [len(x), len(y), len(z)] + self._fields_shape + orig_shape = [len(x), len(y), len(z), *self._fields_shape] flat_shape = orig_shape.copy() flat_shape[axis_ignore] = 1 interpolated_values = np.reshape(interpolated_values, flat_shape) @@ -1380,12 +1457,12 @@ def _interp_py_general( def _interp_py_chunk( self, - xyz_grid: Tuple[ArrayLike[float], ...], + xyz_grid: tuple[ArrayLike[float], ...], cell_inds: ArrayLike[int], cell_ind_min: ArrayLike[int], cell_ind_max: ArrayLike[int], sdf_tol: float, - ) -> Tuple[Tuple[ArrayLike, ...], ArrayLike]: + ) -> tuple[tuple[ArrayLike, ...], ArrayLike]: """For each cell listed in ``cell_inds`` perform interpolation at a rectilinear subarray of xyz_grid given by a (3D) index span (cell_ind_min, cell_ind_max). @@ -1552,7 +1629,7 @@ def _interp_py_chunk( # interpolated_value = value0 * face0_sdf / dist0_sdf + ... # (because face0_sdf / dist0_sdf is linear shape function for vertex0) sdf = -inf * np.ones(num_samples_total) - interpolated = np.zeros([num_samples_total] + self._fields_shape, dtype=self._double_type) + interpolated = np.zeros([num_samples_total, *self._fields_shape], dtype=self._double_type) # coordinates of each sample point sample_xyz = np.zeros((num_samples_total, num_dims)) @@ -1623,7 +1700,7 @@ def sel( x: Union[float, ArrayLike] = None, y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, - method: Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"] = None, + method: Optional[Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"]] = None, **sel_kwargs, ) -> Union[UnstructuredGridDataset, XrDataArray]: """Extract/interpolate data along one or more spatial or non-spatial directions. Must provide at least one argument diff --git a/tidy3d/components/data/unstructured/tetrahedral.py b/tidy3d/components/data/unstructured/tetrahedral.py index 6c7d8ffc16..42ac4b58b1 100644 --- a/tidy3d/components/data/unstructured/tetrahedral.py +++ b/tidy3d/components/data/unstructured/tetrahedral.py @@ -97,6 +97,7 @@ def _from_vtk_obj( remove_unused_points: bool = False, values_type=IndexedDataArray, expect_complex: bool = False, + ignore_invalid_cells: bool = False, ) -> TetrahedralGridDataset: """Initialize from a vtkUnstructuredGrid instance.""" @@ -109,8 +110,19 @@ def _from_vtk_obj( # verify cell_types cells_types = vtk["vtk_to_numpy"](vtk_obj.GetCellTypesArray()) - if not np.all(cells_types == cls._vtk_cell_type()): - raise DataError("Only tetrahedral 'vtkUnstructuredGrid' is currently supported") + invalid_cells = cells_types != cls._vtk_cell_type() + if any(invalid_cells): + if ignore_invalid_cells: + cell_offsets = vtk["vtk_to_numpy"](vtk_obj.GetCells().GetOffsetsArray()) + valid_cell_offsets = cell_offsets[:-1][invalid_cells == 0] + cells_numpy = cells_numpy[ + np.ravel( + valid_cell_offsets[:, None] + + np.arange(cls._cell_num_vertices(), dtype=int)[None, :] + ) + ] + else: + raise DataError("Only tetrahedral 'vtkUnstructuredGrid' is currently supported") # pack point and cell information into Tidy3D arrays num_cells = len(cells_numpy) // cls._cell_num_vertices() @@ -118,14 +130,15 @@ def _from_vtk_obj( cells = CellDataArray( cells_numpy, - coords=dict( - cell_index=np.arange(num_cells), vertex_index=np.arange(cls._cell_num_vertices()) - ), + coords={ + "cell_index": np.arange(num_cells), + "vertex_index": np.arange(cls._cell_num_vertices()), + }, ) points = PointDataArray( points_numpy, - coords=dict(index=np.arange(len(points_numpy)), axis=np.arange(cls._point_dims())), + coords={"index": np.arange(len(points_numpy)), "axis": np.arange(cls._point_dims())}, ) if remove_degenerate_cells: diff --git a/tidy3d/components/data/unstructured/triangular.py b/tidy3d/components/data/unstructured/triangular.py index 21c2416da9..32d54f259b 100644 --- a/tidy3d/components/data/unstructured/triangular.py +++ b/tidy3d/components/data/unstructured/triangular.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Literal, Union +from typing import Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -132,6 +132,7 @@ def _from_vtk_obj( remove_unused_points: bool = False, values_type=IndexedDataArray, expect_complex=None, + ignore_invalid_cells: bool = False, ): """Initialize from a vtkUnstructuredGrid instance.""" @@ -143,12 +144,20 @@ def _from_vtk_obj( cells_numpy = vtk["vtk_to_numpy"](cells_vtk.GetConnectivityArray()) + # verify cell_types cell_offsets = vtk["vtk_to_numpy"](cells_vtk.GetOffsetsArray()) - if not np.all(np.diff(cell_offsets) == cls._cell_num_vertices()): - raise DataError( - "Only triangular 'vtkUnstructuredGrid' or 'vtkPolyData' can be converted into " - "'TriangularGridDataset'." - ) + invalid_cells = np.diff(cell_offsets) != cls._cell_num_vertices() + if np.any(invalid_cells): + if ignore_invalid_cells: + valid_cell_offsets = cell_offsets[:-1][invalid_cells == 0] + cells_numpy = cells_numpy[ + np.ravel(valid_cell_offsets[:, None] + np.arange(3, dtype=int)[None, :]) + ] + else: + raise DataError( + "Only triangular 'vtkUnstructuredGrid' or 'vtkPolyData' can be converted into " + "'TriangularGridDataset'." + ) points_numpy = vtk["vtk_to_numpy"](vtk_obj.GetPoints().GetData()) @@ -159,7 +168,7 @@ def _from_vtk_obj( # detect zero size dimension bounds = np.max(points_numpy, axis=0) - np.min(points_numpy, axis=0) - zero_dims = np.where(np.isclose(bounds, 0))[0] + zero_dims = np.where(np.isclose(bounds, 0, atol=1e-6))[0] if len(zero_dims) != 1: raise DataError( @@ -180,14 +189,15 @@ def _from_vtk_obj( cells = CellDataArray( cells_numpy, - coords=dict( - cell_index=np.arange(num_cells), vertex_index=np.arange(cls._cell_num_vertices()) - ), + coords={ + "cell_index": np.arange(num_cells), + "vertex_index": np.arange(cls._cell_num_vertices()), + }, ) points = PointDataArray( points_2d_numpy, - coords=dict(index=np.arange(len(points_numpy)), axis=np.arange(cls._point_dims())), + coords={"index": np.arange(len(points_numpy)), "axis": np.arange(cls._point_dims())}, ) if remove_degenerate_cells: @@ -304,7 +314,7 @@ def _spatial_interp( x: Union[float, ArrayLike], y: Union[float, ArrayLike], z: Union[float, ArrayLike], - fill_value: Union[float, Literal["extrapolate"]] = None, + fill_value: Optional[Union[float, Literal["extrapolate"]]] = None, use_vtk: bool = False, method: Literal["linear", "nearest"] = "linear", ignore_normal_pos: bool = True, @@ -376,7 +386,7 @@ def _spatial_interp( interp_inplane, [len(np.atleast_1d(comp)) for comp in [x, y, z]] + self._fields_shape ) - coords_dict = dict(x=x, y=y, z=z) + coords_dict = {"x": x, "y": y, "z": z} coords_dict.update(self._values_coords_dict) if len(self._values_coords_dict) == 0: @@ -443,7 +453,7 @@ def sel( x: Union[float, ArrayLike] = None, y: Union[float, ArrayLike] = None, z: Union[float, ArrayLike] = None, - method: Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"] = None, + method: Optional[Literal["None", "nearest", "pad", "ffill", "backfill", "bfill"]] = None, **sel_kwargs, ) -> XrDataArray: """Extract/interpolate data along one or more spatial or non-spatial directions. Must provide at least one argument @@ -574,11 +584,11 @@ def plot( grid: bool = True, cbar: bool = True, cmap: str = "viridis", - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, shading: Literal["gourand", "flat"] = "gouraud", - cbar_kwargs: Dict = None, - pcolor_kwargs: Dict = None, + cbar_kwargs: Optional[dict] = None, + pcolor_kwargs: Optional[dict] = None, ) -> Ax: """Plot the data field and/or the unstructured grid. @@ -604,6 +614,8 @@ def plot( Type of shading to use when plotting the data field. cbar_kwargs : Dict = {} Additional parameters passed to colorbar object. + pcolor_kwargs: Dict = {} + Additional parameters passed to ax.tripcolor() Returns ------- @@ -663,5 +675,5 @@ def get_cell_volumes(self): v0 = self.points[self.cells.sel(vertex_index=0)] e01 = self.points[self.cells.sel(vertex_index=1)] - v0 e02 = self.points[self.cells.sel(vertex_index=2)] - v0 - - return 0.5 * np.abs(np.cross(e01, e02)) + areas = e01[:, 0] * e02[:, 1] - e01[:, 1] * e02[:, 0] + return 0.5 * np.abs(areas) diff --git a/tidy3d/components/data/utils.py b/tidy3d/components/data/utils.py index 9e64765fd3..e2c96c0031 100644 --- a/tidy3d/components/data/utils.py +++ b/tidy3d/components/data/utils.py @@ -7,7 +7,8 @@ import numpy as np import xarray as xr -from ..types import ArrayLike, annotate_type +from tidy3d.components.types import ArrayLike, annotate_type + from .data_array import DataArray, SpatialDataArray from .unstructured.base import UnstructuredGridDataset from .unstructured.tetrahedral import TetrahedralGridDataset diff --git a/tidy3d/components/data/validators.py b/tidy3d/components/data/validators.py index 98d49ef56b..4988c36044 100644 --- a/tidy3d/components/data/validators.py +++ b/tidy3d/components/data/validators.py @@ -1,9 +1,13 @@ # special validators for Datasets +from __future__ import annotations + +from typing import Optional import numpy as np import pydantic.v1 as pd -from ...exceptions import ValidationError +from tidy3d.exceptions import ValidationError + from .data_array import DataArray from .dataset import AbstractFieldDataset, ScalarFieldDataArray @@ -19,7 +23,7 @@ def no_nans(cls, val): if val is None: return val - def error_if_has_nans(value, identifier: str = None) -> None: + def error_if_has_nans(value, identifier: Optional[str] = None) -> None: """Recursively check if value (or iterable) has nans and error if so.""" def has_nans(values) -> bool: diff --git a/tidy3d/components/data/zbf.py b/tidy3d/components/data/zbf.py index 947953d00c..d05d058d25 100644 --- a/tidy3d/components/data/zbf.py +++ b/tidy3d/components/data/zbf.py @@ -7,7 +7,7 @@ import numpy as np import pydantic.v1 as pd -from ..base import Tidy3dBaseModel +from tidy3d.components.base import Tidy3dBaseModel class ZBFData(Tidy3dBaseModel): @@ -118,7 +118,7 @@ def read_zbf(filename: str) -> ZBFData: except KeyError: raise KeyError( f"Invalid units specified in the zbf file (expected '0', '1', '2', or '3', got '{units}')." - ) + ) from None # load E field Ex_real = np.asarray(rawx[0::2]).reshape(nx, ny) diff --git a/tidy3d/components/dispersion_fitter.py b/tidy3d/components/dispersion_fitter.py index 07fecf866e..8c1be3a827 100644 --- a/tidy3d/components/dispersion_fitter.py +++ b/tidy3d/components/dispersion_fitter.py @@ -2,16 +2,15 @@ from __future__ import annotations -from typing import Optional, Tuple +from typing import Optional import numpy as np -import scipy from pydantic.v1 import Field, NonNegativeFloat, PositiveFloat, PositiveInt, validator -from rich.progress import Progress -from ..constants import fp_eps -from ..exceptions import ValidationError -from ..log import get_logging_console, log +from tidy3d.constants import fp_eps +from tidy3d.exceptions import ValidationError +from tidy3d.log import Progress, get_logging_console, log + from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing from .types import ArrayComplex1D, ArrayComplex2D, ArrayFloat1D, ArrayFloat2D @@ -111,7 +110,7 @@ def _extrema_loss_freq_finder(areal, aimag, creal, cimag): class AdvancedFastFitterParam(Tidy3dBaseModel): """Advanced fast fitter parameters.""" - loss_bounds: Tuple[float, float] = Field( + loss_bounds: tuple[float, float] = Field( (0, np.inf), title="Loss bounds", description="Bounds (lower, upper) on Im[resp]. Default corresponds to only passivity. " @@ -121,7 +120,7 @@ class AdvancedFastFitterParam(Tidy3dBaseModel): "A finite upper bound may be helpful when fitting lossless materials. " "In this case, consider also increasing the weight for fitting the imaginary part.", ) - weights: Tuple[NonNegativeFloat, NonNegativeFloat] = Field( + weights: tuple[NonNegativeFloat, NonNegativeFloat] = Field( None, title="Weights", description="Weights (real, imag) in objective function for fitting. The weights " @@ -350,7 +349,7 @@ def complex_poles(self) -> ArrayFloat1D: return self.poles[np.iscomplex(self.poles)] @classmethod - def get_default_weights(cls, eps: ArrayComplex1D) -> Tuple[float, float]: + def get_default_weights(cls, eps: ArrayComplex1D) -> tuple[float, float]: """Default weights based on real and imaginary part of eps.""" rms = np.array([np.sqrt(np.mean(x**2)) for x in (np.real(eps), np.imag(eps))]) rms = np.maximum(RMS_MIN, rms) @@ -360,7 +359,7 @@ def get_default_weights(cls, eps: ArrayComplex1D) -> Tuple[float, float]: return tuple(weights) @cached_property - def pole_residue(self) -> Tuple[float, ArrayComplex1D, ArrayComplex1D]: + def pole_residue(self) -> tuple[float, ArrayComplex1D, ArrayComplex1D]: """Parameters for pole-residue model in original units.""" if self.eps_inf is None or self.poles is None: return 1, [], [] @@ -492,6 +491,7 @@ def real_weighted_matrix(self, matrix: ArrayComplex2D) -> ArrayFloat2D: def iterate_poles(self) -> FastFitterData: """Perform a single iteration of the pole-updating procedure.""" + from scipy import optimize def compute_zeros(residues: ArrayComplex1D, d_tilde: float) -> ArrayComplex1D: """Compute the zeros from the residues.""" @@ -563,7 +563,7 @@ def compute_zeros(residues: ArrayComplex1D, d_tilde: float) -> ArrayComplex1D: ) # solve the least squares problem - x_vector = scipy.optimize.lsq_linear(a_matrix_real, b_vector_real).x + x_vector = optimize.lsq_linear(a_matrix_real, b_vector_real).x # unpack the solution residues = np.zeros(len(self.poles), dtype=complex) @@ -593,6 +593,8 @@ def compute_zeros(residues: ArrayComplex1D, d_tilde: float) -> ArrayComplex1D: def fit_residues(self) -> FastFitterData: """Fit residues.""" + from scipy import optimize + # build the matrices if self.optimize_eps_inf: poly_len = 1 @@ -609,7 +611,7 @@ def fit_residues(self) -> FastFitterData: # solve the least squares problem bounds = (-np.inf * np.ones(a_matrix.shape[1]), np.inf * np.ones(a_matrix.shape[1])) bounds[0][-1] = 1 # eps_inf >= 1 - x_vector = scipy.optimize.lsq_linear(a_matrix_real, b_vector_real).x + x_vector = optimize.lsq_linear(a_matrix_real, b_vector_real).x # unpack the solution residues = np.zeros(len(self.poles), dtype=complex) @@ -647,8 +649,9 @@ def iterate_fit(self) -> FastFitterData: return model - def iterate_passivity(self, passivity_omega: ArrayFloat1D) -> Tuple[FastFitterData, int]: + def iterate_passivity(self, passivity_omega: ArrayFloat1D) -> tuple[FastFitterData, int]: """Iterate passivity enforcement algorithm.""" + from scipy import optimize size = len(self.real_poles) + 2 * len(self.complex_poles) constraint_matrix = np.imag(self.pole_matrix_omega(passivity_omega)) @@ -682,7 +685,7 @@ def jac(dx): x0 = np.zeros(size) err = np.amin(c_vector - constraint_matrix @ x0) - result = scipy.optimize.minimize( + result = optimize.minimize( loss, x0=x0, jac=jac, constraints=cons, method="SLSQP", options=opt ) x_vector = result.x @@ -724,7 +727,7 @@ def enforce_passivity( def _fit_fixed_parameters( - num_poles_range: Tuple[PositiveInt, PositiveInt], model: FastFitterData + num_poles_range: tuple[PositiveInt, PositiveInt], model: FastFitterData ) -> FastFitterData: def fit_non_passive(model: FastFitterData) -> FastFitterData: best_model = model @@ -755,11 +758,11 @@ def fit( resp_data: ArrayComplex1D, min_num_poles: PositiveInt = 1, max_num_poles: PositiveInt = DEFAULT_MAX_POLES, - resp_inf: float = None, + resp_inf: Optional[float] = None, tolerance_rms: NonNegativeFloat = DEFAULT_TOLERANCE_RMS, advanced_param: AdvancedFastFitterParam = None, scale_factor: PositiveFloat = 1, -) -> Tuple[Tuple[float, ArrayComplex1D, ArrayComplex1D], float]: +) -> tuple[tuple[float, ArrayComplex1D, ArrayComplex1D], float]: """Fit data using a fast fitting algorithm. Note @@ -818,12 +821,11 @@ def fit( Returns ------- - Tuple[Tuple[float, ArrayComplex1D, ArrayComplex1D], float] + tuple[tuple[float, ArrayComplex1D, ArrayComplex1D], float] Best fitting result: (dispersive medium parameters, weighted RMS error). The dispersive medium parameters have the form (resp_inf, poles, residues) and are in the original unscaled units. """ - if max_num_poles < min_num_poles: raise ValidationError( "Dispersion fitter cannot have 'max_num_poles' less than 'min_num_poles'." @@ -840,7 +842,7 @@ def fit( advanced_param=advanced_param or AdvancedFastFitterParam(), scale_factor=scale_factor, ) - log.info(f"Fitting weights=({init_model.weights[0]:.3g}, " f"{init_model.weights[1]:.3g}).") + log.info(f"Fitting weights=({init_model.weights[0]:.3g}, {init_model.weights[1]:.3g}).") def make_configs(): configs = [[p] for p in range(max(min_num_poles // 2, 1), max_num_poles + 1)] @@ -851,9 +853,9 @@ def make_configs(): init_model.optimize_eps_inf, ]: if setting is None: - configs = [c + [r] for c in configs for r in [True, False]] + configs = [[*c, r] for c in configs for r in [True, False]] else: - configs = [c + [r] for c in configs for r in [setting]] + configs = [[*c, r] for c in configs for r in [setting]] return configs best_model = init_model @@ -862,88 +864,80 @@ def make_configs(): configs = make_configs() - with Progress(console=get_logging_console()) as progress: + with Progress( + console=get_logging_console(), show_progress=init_model.show_progress + ) as progress: task = progress.add_task( - f"Fitting to weighted RMS of {tolerance_rms}...", + description=f"Fitting to weighted RMS of {tolerance_rms}...", total=len(configs), visible=init_model.show_progress, ) - while not progress.finished: - # try different initial pole configurations - for num_poles, relaxed, smooth, logspacing, optimize_eps_inf in configs: - model = init_model.updated_copy( - num_poles=num_poles, - relaxed=relaxed, - smooth=smooth, - logspacing=logspacing, - optimize_eps_inf=optimize_eps_inf, + # try different initial pole configurations + for num_poles, relaxed, smooth, logspacing, optimize_eps_inf in configs: + model = init_model.updated_copy( + num_poles=num_poles, + relaxed=relaxed, + smooth=smooth, + logspacing=logspacing, + optimize_eps_inf=optimize_eps_inf, + ) + model = _fit_fixed_parameters((min_num_poles, max_num_poles), model) + + if model.rms_error < best_model.rms_error: + log.debug( + f"Fitter: possible improved fit with " + f"rms_error={model.rms_error:.3g} found using " + f"relaxed={model.relaxed}, " + f"smooth={model.smooth}, " + f"logspacing={model.logspacing}, " + f"optimize_eps_inf={model.optimize_eps_inf}, " + f"loss_in_bounds={model.loss_in_bounds}, " + f"passivity_optimized={model.passivity_optimized}, " + f"sellmeier_passivity={model.sellmeier_passivity}." ) - model = _fit_fixed_parameters((min_num_poles, max_num_poles), model) - - if model.rms_error < best_model.rms_error: - log.debug( - f"Fitter: possible improved fit with " - f"rms_error={model.rms_error:.3g} found using " - f"relaxed={model.relaxed}, " - f"smooth={model.smooth}, " - f"logspacing={model.logspacing}, " - f"optimize_eps_inf={model.optimize_eps_inf}, " - f"loss_in_bounds={model.loss_in_bounds}, " - f"passivity_optimized={model.passivity_optimized}, " - f"sellmeier_passivity={model.sellmeier_passivity}." - ) - if model.loss_in_bounds and model.sellmeier_passivity: - best_model = model - else: - if ( - not warned_about_passivity_num_iters - and model.passivity_num_iters_too_small - ): - warned_about_passivity_num_iters = True - log.warning( - "Did not finish enforcing passivity in dispersion fitter. " - "If the fit is not good enough, consider increasing " - "'AdvancedFastFitterParam.passivity_num_iters'." - ) - if ( - not warned_about_slsqp_constraint_scale - and model.slsqp_constraint_scale_too_small - ): - warned_about_slsqp_constraint_scale = True - log.warning( - "SLSQP constraint scale may be too small. " - "If the fit is not good enough, consider increasing " - "'AdvancedFastFitterParam.slsqp_constraint_scale'." - ) + if model.loss_in_bounds and model.sellmeier_passivity: + best_model = model + else: + if not warned_about_passivity_num_iters and model.passivity_num_iters_too_small: + warned_about_passivity_num_iters = True + log.warning( + "Did not finish enforcing passivity in dispersion fitter. " + "If the fit is not good enough, consider increasing " + "'AdvancedFastFitterParam.passivity_num_iters'." + ) + if ( + not warned_about_slsqp_constraint_scale + and model.slsqp_constraint_scale_too_small + ): + warned_about_slsqp_constraint_scale = True + log.warning( + "SLSQP constraint scale may be too small. " + "If the fit is not good enough, consider increasing " + "'AdvancedFastFitterParam.slsqp_constraint_scale'." + ) + progress.update( + task, + advance=1, + description=f"Best weighted RMS error so far: {best_model.rms_error:.3g}", + refresh=True, + ) + + # if below tolerance, return + if best_model.rms_error < tolerance_rms: progress.update( task, - advance=1, - description=f"Best weighted RMS error so far: {best_model.rms_error:.3g}", + completed=len(configs), + description=f"Best weighted RMS error: {best_model.rms_error:.3g}", refresh=True, ) - - # if below tolerance, return - if best_model.rms_error < tolerance_rms: - progress.update( - task, - completed=len(configs), - description=f"Best weighted RMS error: {best_model.rms_error:.3g}", - refresh=True, - ) - log.info( - "Found optimal fit with weighted RMS error %.3g", - best_model.rms_error, - ) - if best_model.show_unweighted_rms: - log.info( - "Unweighted RMS error %.3g", - best_model.unweighted_rms_error, - ) - return ( - best_model.pole_residue, - best_model.rms_error, - ) + log.info(f"Found optimal fit with weighted RMS error {best_model.rms_error:.3g}") + if best_model.show_unweighted_rms: + log.info(f"Unweighted RMS error {best_model.unweighted_rms_error:.3g}") + return ( + best_model.pole_residue, + best_model.rms_error, + ) # if exited loop, did not reach tolerance (warn) progress.update( @@ -954,16 +948,73 @@ def make_configs(): ) log.warning( - "Unable to fit with weighted RMS error under 'tolerance_rms' of %.3g", tolerance_rms + f"Unable to fit with weighted RMS error under 'tolerance_rms' of {tolerance_rms:.3g}" ) - log.info("Returning best fit with weighted RMS error %.3g", best_model.rms_error) + log.info(f"Returning best fit with weighted RMS error {best_model.rms_error:.3g}") if best_model.show_unweighted_rms: - log.info( - "Unweighted RMS error %.3g", - best_model.unweighted_rms_error, - ) + log.info(f"Unweighted RMS error {best_model.unweighted_rms_error:.3g}") return ( best_model.pole_residue, best_model.rms_error, ) + + +def constant_loss_tangent_model( + eps_real: float, + loss_tangent: float, + frequency_range: tuple[float, float], + max_num_poles: PositiveInt = DEFAULT_MAX_POLES, + number_sampling_frequency: PositiveInt = 10, + tolerance_rms: NonNegativeFloat = DEFAULT_TOLERANCE_RMS, + scale_factor: float = 1, + show_progress: bool = True, +) -> tuple[tuple[float, ArrayComplex1D, ArrayComplex1D], float]: + """Fit a constant loss tangent material model. + + Parameters + ---------- + eps_real : float + Real part of permittivity + loss_tangent : float + Loss tangent. + frequency_range : tuple[float, float] + Freqquency range for the material to exhibit constant loss tangent response. + max_num_poles : PositiveInt, optional + Maximum number of poles in the model. + number_sampling_frequency : PositiveInt, optional + Number of sampling frequencies to compute RMS error for fitting. + tolerance_rms : float, optional + Weighted RMS error below which the fit is successful and the result is returned. + scale_factor : PositiveFloat, optional + Factor to rescale frequency by before fitting. + show_progress : bool + Whether to show a progress bar. + + Returns + ------- + tuple[tuple[float, ArrayComplex1D, ArrayComplex1D], float] + Best fitting result: (dispersive medium parameters, weighted RMS error). + The dispersive medium parameters have the form (resp_inf, poles, residues) + and are in the original unscaled units. + """ + if number_sampling_frequency < 2: + frequencies = np.array([np.mean(frequency_range)]) + else: + frequencies = np.linspace(frequency_range[0], frequency_range[1], number_sampling_frequency) + eps_real_array = np.ones_like(frequencies) * eps_real + loss_tangent_array = np.ones_like(frequencies) * loss_tangent + + omega_data = frequencies * 2 * np.pi + eps_complex = eps_real_array * (1 + 1j * loss_tangent_array) + + advanced_param = AdvancedFastFitterParam(show_progress=show_progress) + + return fit( + omega_data=omega_data, + resp_data=eps_complex, + max_num_poles=max_num_poles, + tolerance_rms=tolerance_rms, + scale_factor=scale_factor, + advanced_param=advanced_param, + ) diff --git a/tidy3d/components/eme/data/dataset.py b/tidy3d/components/eme/data/dataset.py index f0dcd772c8..33f45cef2c 100644 --- a/tidy3d/components/eme/data/dataset.py +++ b/tidy3d/components/eme/data/dataset.py @@ -4,14 +4,14 @@ import pydantic.v1 as pd -from ...data.data_array import ( +from tidy3d.components.data.data_array import ( EMECoefficientDataArray, EMEModeIndexDataArray, EMEScalarFieldDataArray, EMEScalarModeFieldDataArray, EMESMatrixDataArray, ) -from ...data.dataset import Dataset, ElectromagneticFieldDataset +from tidy3d.components.data.dataset import Dataset, ElectromagneticFieldDataset class EMESMatrixDataset(Dataset): diff --git a/tidy3d/components/eme/data/monitor_data.py b/tidy3d/components/eme/data/monitor_data.py index 7014562e11..65817a6de7 100644 --- a/tidy3d/components/eme/data/monitor_data.py +++ b/tidy3d/components/eme/data/monitor_data.py @@ -6,9 +6,18 @@ import pydantic.v1 as pd -from ...base_sim.data.monitor_data import AbstractMonitorData -from ...data.monitor_data import ElectromagneticFieldData, ModeSolverData, PermittivityData -from ..monitor import EMECoefficientMonitor, EMEFieldMonitor, EMEModeSolverMonitor +from tidy3d.components.base_sim.data.monitor_data import AbstractMonitorData +from tidy3d.components.data.monitor_data import ( + ElectromagneticFieldData, + ModeSolverData, + PermittivityData, +) +from tidy3d.components.eme.monitor import ( + EMECoefficientMonitor, + EMEFieldMonitor, + EMEModeSolverMonitor, +) + from .dataset import EMECoefficientDataset, EMEFieldDataset, EMEModeSolverDataset diff --git a/tidy3d/components/eme/data/sim_data.py b/tidy3d/components/eme/data/sim_data.py index ef15a45c55..03d16e65d9 100644 --- a/tidy3d/components/eme/data/sim_data.py +++ b/tidy3d/components/eme/data/sim_data.py @@ -2,18 +2,21 @@ from __future__ import annotations -from typing import List, Literal, Optional, Tuple, Union +from typing import Literal, Optional, Union import numpy as np import pydantic.v1 as pd -from ....exceptions import SetupError -from ...base import cached_property -from ...data.data_array import EMEScalarFieldDataArray, EMESMatrixDataArray -from ...data.monitor_data import FieldData, ModeData, ModeSolverData -from ...data.sim_data import AbstractYeeGridSimulationData -from ...types import annotate_type -from ..simulation import EMESimulation +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import EMEScalarFieldDataArray, EMESMatrixDataArray +from tidy3d.components.data.monitor_data import FieldData, ModeData, ModeSolverData +from tidy3d.components.data.sim_data import AbstractYeeGridSimulationData +from tidy3d.components.eme.simulation import EMESimulation +from tidy3d.components.geometry.base import Box +from tidy3d.components.types import annotate_type +from tidy3d.exceptions import SetupError +from tidy3d.log import log + from .dataset import EMESMatrixDataset from .monitor_data import EMEFieldData, EMEModeSolverData, EMEMonitorDataType @@ -25,7 +28,7 @@ class EMESimulationData(AbstractYeeGridSimulationData): ..., title="EME simulation", description="EME simulation associated with this data." ) - data: Tuple[annotate_type(EMEMonitorDataType), ...] = pd.Field( + data: tuple[annotate_type(EMEMonitorDataType), ...] = pd.Field( ..., title="Monitor Data", description="List of EME monitor data " @@ -36,15 +39,25 @@ class EMESimulationData(AbstractYeeGridSimulationData): None, title="S Matrix", description="Scattering matrix of the EME simulation." ) - port_modes: Optional[EMEModeSolverData] = pd.Field( + port_modes_raw: Optional[EMEModeSolverData] = pd.Field( None, title="Port Modes", description="Modes associated with the two ports of the EME device. " - "The scattering matrix is expressed in this basis.", + "The scattering matrix is expressed in this basis. " + "Note: these modes are not symmetry expanded; use 'port_modes' instead.", ) + @cached_property + def port_modes(self): + """Modes associated with the two ports of the EME device. + The scattering matrix is expressed in this basis. + Note: these modes are symmetry expanded.""" + if self.port_modes_raw is None: + return None + return self.port_modes_raw.symmetry_expanded_copy + def _extract_mode_solver_data( - self, data: EMEModeSolverData, eme_cell_index: int, sweep_index: int = None + self, data: EMEModeSolverData, eme_cell_index: int, sweep_index: Optional[int] = None ) -> ModeSolverData: """Extract :class:`.ModeSolverData` at a given ``eme_cell_index``. Assumes the :class:`.EMEModeSolverMonitor` spans the entire simulation and has @@ -71,14 +84,31 @@ def _extract_mode_solver_data( } monitor = self.simulation.mode_solver_monitors[eme_cell_index] - monitor = monitor.updated_copy( - colocate=data.monitor.colocate, + monitor = monitor.updated_copy(colocate=data.monitor.colocate) + box = Box.from_bounds( + *Box.bounds_intersection(monitor.geometry.bounds, data.monitor.geometry.bounds) ) + size = box.size + center = box.center + if size.count(0.0) == 1: + monitor = monitor.updated_copy(size=size, center=center) + else: + log.warning( + "'ModeSolverData' extracted from 'EMEModeSolverData' " + "is not 2D, so it may not be possible to compute " + "certain derived quantities, like the flux." + ) grid_expanded = self.simulation.discretize_monitor(monitor=monitor) - return ModeSolverData(**update_dict, monitor=monitor, grid_expanded=grid_expanded) + return ModeSolverData( + **update_dict, + monitor=monitor, + grid_expanded=grid_expanded, + symmetry=data.symmetry, + symmetry_center=data.symmetry_center, + ) @cached_property - def port_modes_tuple(self) -> Tuple[ModeSolverData, ModeSolverData]: + def port_modes_tuple(self) -> tuple[ModeSolverData, ModeSolverData]: """Port modes as a tuple ``(port_modes_1, port_modes_2)``.""" if self.port_modes is None: raise SetupError( @@ -101,7 +131,7 @@ def port_modes_tuple(self) -> Tuple[ModeSolverData, ModeSolverData]: return port_modes_1, port_modes_2 @cached_property - def port_modes_list_sweep(self) -> List[Tuple[ModeSolverData, ModeSolverData]]: + def port_modes_list_sweep(self) -> list[tuple[ModeSolverData, ModeSolverData]]: """Port modes as a list of tuples ``(port_modes_1, port_modes_2)``. There is one entry for every sweep index if the port modes vary with sweep index.""" if self.port_modes is None: @@ -287,18 +317,30 @@ def smatrix_in_basis( data21[:, sweep_index, :, :] = S21.to_numpy() data22[:, sweep_index, :, :] = S22.to_numpy() - coords11 = dict( - f=f, sweep_index=sweep_indices, mode_index_out=mode_index_1, mode_index_in=mode_index_1 - ) - coords12 = dict( - f=f, sweep_index=sweep_indices, mode_index_out=mode_index_1, mode_index_in=mode_index_2 - ) - coords21 = dict( - f=f, sweep_index=sweep_indices, mode_index_out=mode_index_2, mode_index_in=mode_index_1 - ) - coords22 = dict( - f=f, sweep_index=sweep_indices, mode_index_out=mode_index_2, mode_index_in=mode_index_2 - ) + coords11 = { + "f": f, + "sweep_index": sweep_indices, + "mode_index_out": mode_index_1, + "mode_index_in": mode_index_1, + } + coords12 = { + "f": f, + "sweep_index": sweep_indices, + "mode_index_out": mode_index_1, + "mode_index_in": mode_index_2, + } + coords21 = { + "f": f, + "sweep_index": sweep_indices, + "mode_index_out": mode_index_2, + "mode_index_in": mode_index_1, + } + coords22 = { + "f": f, + "sweep_index": sweep_indices, + "mode_index_out": mode_index_2, + "mode_index_in": mode_index_2, + } xrS11 = EMESMatrixDataArray(data11, coords=coords11) xrS12 = EMESMatrixDataArray(data12, coords=coords12) xrS21 = EMESMatrixDataArray(data21, coords=coords21) @@ -389,15 +431,15 @@ def field_in_basis( shape[-2] = 1 field_data[field_key] = np.empty(shape, dtype=complex) field_data[field_key][:] = np.nan - field_coords[field_key] = dict( - x=field_comp.x.to_numpy(), - y=field_comp.y.to_numpy(), - z=field_comp.z.to_numpy(), - f=field_comp.f.to_numpy(), - sweep_index=sweep_indices, - eme_port_index=[port_index], - mode_index=mode_index, - ) + field_coords[field_key] = { + "x": field_comp.x.to_numpy(), + "y": field_comp.y.to_numpy(), + "z": field_comp.z.to_numpy(), + "f": field_comp.f.to_numpy(), + "sweep_index": sweep_indices, + "eme_port_index": [port_index], + "mode_index": mode_index, + } # populate the arrays for sweep_index in sweep_indices: diff --git a/tidy3d/components/eme/grid.py b/tidy3d/components/eme/grid.py index 18c0403b3e..d197c60677 100644 --- a/tidy3d/components/eme/grid.py +++ b/tidy3d/components/eme/grid.py @@ -3,19 +3,19 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Dict, List, Literal, Optional, Tuple, Union +from typing import Literal, Optional, Union import numpy as np import pydantic.v1 as pd -from ...constants import RADIAN, fp_eps, inf -from ...exceptions import SetupError, ValidationError -from ..base import Tidy3dBaseModel, skip_if_fields_missing -from ..geometry.base import Box -from ..grid.grid import Coords1D -from ..mode_spec import ModeSpec -from ..structure import Structure -from ..types import ArrayFloat1D, Axis, Coordinate, Size, TrackFreq +from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing +from tidy3d.components.geometry.base import Box +from tidy3d.components.grid.grid import Coords1D +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.structure import Structure +from tidy3d.components.types import ArrayFloat1D, Axis, Coordinate, Size, TrackFreq +from tidy3d.constants import RADIAN, fp_eps, inf +from tidy3d.exceptions import SetupError, ValidationError # grid limits MAX_NUM_MODES = 100 @@ -54,6 +54,15 @@ class EMEModeSpec(ModeSpec): units=RADIAN, ) + precision: Literal["auto", "single", "double"] = pd.Field( + "auto", + title="single, double, or automatic precision in mode solver", + description="The solver will be faster and using less memory under " + "single precision, but more accurate under double precision. " + "Choose ``'auto'`` to apply double precision if the simulation contains a good " + "conductor, single precision otherwise.", + ) + # this method is not supported because not all ModeSpec features are supported # @classmethod # def _from_mode_spec(cls, mode_spec: ModeSpec) -> EMEModeSpec: @@ -74,19 +83,9 @@ class EMEModeSpec(ModeSpec): def _to_mode_spec(self) -> ModeSpec: """Convert to ordinary :class:`.ModeSpec`.""" - return ModeSpec( - num_modes=self.num_modes, - target_neff=self.target_neff, - num_pml=self.num_pml, - filter_pol=self.filter_pol, - angle_theta=self.angle_theta, - angle_phi=self.angle_phi, - precision=self.precision, - bend_radius=self.bend_radius, - bend_axis=self.bend_axis, - track_freq=self.track_freq, - group_index_step=self.group_index_step, - ) + ms_dict = self.dict() + ms_dict.pop("type") + return ModeSpec.parse_obj(ms_dict) class EMEGridSpec(Tidy3dBaseModel, ABC): @@ -163,7 +162,7 @@ def num_virtual_cells(self) -> int: """Number of virtual cells in this EME grid spec.""" return len(self.virtual_cell_indices) - def _updated_copy_num_reps(self, num_reps: Dict[str, pd.PositiveInt]) -> EMEGridSpec: + def _updated_copy_num_reps(self, num_reps: dict[str, pd.PositiveInt]) -> EMEGridSpec: """Update ``num_reps`` of named subgrids.""" if self.name is not None: new_num_reps = num_reps.get(self.name) @@ -172,7 +171,7 @@ def _updated_copy_num_reps(self, num_reps: Dict[str, pd.PositiveInt]) -> EMEGrid return self @property - def _cell_index_pairs(self) -> List[pd.NonNegativeInt]: + def _cell_index_pairs(self) -> list[pd.NonNegativeInt]: """Pairs of adjacent cell indices.""" cell_indices = self.virtual_cell_indices pairs = [] @@ -246,10 +245,10 @@ class EMEExplicitGrid(EMEGridSpec): ... ) """ - mode_specs: List[EMEModeSpec] = pd.Field( + mode_specs: list[EMEModeSpec] = pd.Field( ..., title="Mode Specifications", - description="Mode specifications for each cell " "in the explicit EME grid.", + description="Mode specifications for each cell in the explicit EME grid.", ) boundaries: ArrayFloat1D = pd.Field( @@ -270,7 +269,7 @@ def _validate_boundaries(cls, val, values): boundaries = val if len(mode_specs) - 1 != len(boundaries): raise ValidationError( - "There must be exactly one fewer item in 'boundaries' than " "in 'mode_specs'." + "There must be exactly one fewer item in 'boundaries' than in 'mode_specs'." ) if len(boundaries) > 0: rmin = boundaries[0] @@ -310,7 +309,7 @@ def make_grid(self, center: Coordinate, size: Size, axis: Axis) -> EMEGrid: "The last item in 'boundaries' is outside the simulation domain." ) - boundaries = [sim_rmin] + list(self.boundaries) + [sim_rmax] + boundaries = [sim_rmin, *list(self.boundaries), sim_rmax] return EMEGrid( boundaries=boundaries, center=center, @@ -321,7 +320,7 @@ def make_grid(self, center: Coordinate, size: Size, axis: Axis) -> EMEGrid: @classmethod def from_structures( - cls, structures: List[Structure], axis: Axis, mode_spec: EMEModeSpec, **kwargs + cls, structures: list[Structure], axis: Axis, mode_spec: EMEModeSpec, **kwargs ) -> EMEExplicitGrid: """Create an explicit EME grid with boundaries aligned with structure bounding boxes. Every cell in the resulting grid @@ -398,7 +397,7 @@ class EMECompositeGrid(EMEGridSpec): ... ) """ - subgrids: List[EMESubgridType] = pd.Field( + subgrids: list[EMESubgridType] = pd.Field( ..., title="Subgrids", description="Subgrids in the composite grid." ) @@ -419,8 +418,7 @@ def _validate_subgrid_boundaries(cls, val, values): subgrid_boundaries = val if len(subgrids) - 1 != len(subgrid_boundaries): raise ValidationError( - "There must be exactly one fewer item in 'subgrid_boundaries' than " - "in 'subgrids'." + "There must be exactly one fewer item in 'subgrid_boundaries' than in 'subgrids'." ) rmin = subgrid_boundaries[0] for rmax in subgrid_boundaries[1:]: @@ -431,7 +429,7 @@ def _validate_subgrid_boundaries(cls, val, values): def subgrid_bounds( self, center: Coordinate, size: Size, axis: Axis - ) -> List[Tuple[float, float]]: + ) -> list[tuple[float, float]]: """Subgrid bounds: a list of pairs (rmin, rmax) of the bounds of the subgrids along the propagation axis. @@ -524,7 +522,7 @@ def virtual_cell_indices(self) -> int: inds += [ind + start_ind for ind in subgrid.virtual_cell_indices] return list(inds) * self.num_reps - def _updated_copy_num_reps(self, num_reps: Dict[str, pd.PositiveInt]) -> EMEGridSpec: + def _updated_copy_num_reps(self, num_reps: dict[str, pd.PositiveInt]) -> EMEGridSpec: """Update ``num_reps`` of named subgrids.""" new_self = super()._updated_copy_num_reps(num_reps=num_reps) new_subgrids = [ @@ -535,11 +533,11 @@ def _updated_copy_num_reps(self, num_reps: Dict[str, pd.PositiveInt]) -> EMEGrid @classmethod def from_structure_groups( cls, - structure_groups: List[List[Structure]], + structure_groups: list[list[Structure]], axis: Axis, - mode_specs: List[EMEModeSpec], - names: List[str] = None, - num_reps: List[pd.PositiveInt] = None, + mode_specs: list[EMEModeSpec], + names: Optional[list[str]] = None, + num_reps: Optional[list[pd.PositiveInt]] = None, ) -> EMECompositeGrid: """Create a composite EME grid with boundaries aligned with structure bounding boxes. @@ -598,7 +596,7 @@ def from_structure_groups( raise ValidationError("The list 'structure_groups' cannot be empty.") if len(mode_specs) != len(structure_groups): raise ValidationError( - "The lists 'mode_specs' and 'structure_groups' must " "have the same length." + "The lists 'mode_specs' and 'structure_groups' must have the same length." ) subgrids = [] @@ -612,7 +610,7 @@ def from_structure_groups( if names is not None: if len(names) != len(structure_groups): raise ValidationError( - "The lists 'names' and 'structure_groups' must " "have the same length." + "The lists 'names' and 'structure_groups' must have the same length." ) for i in range(len(subgrids)): subgrids[i] = subgrids[i].updated_copy(name=names[i]) @@ -620,7 +618,7 @@ def from_structure_groups( if num_reps is not None: if len(num_reps) != len(structure_groups): raise ValidationError( - "The lists 'num_reps' and 'structure_groups' must " "have the same length." + "The lists 'num_reps' and 'structure_groups' must have the same length." ) for i in range(len(subgrids)): subgrids[i] = subgrids[i].updated_copy(num_reps=num_reps[i]) @@ -676,7 +674,7 @@ class EMEGrid(Box): ..., title="Propagation axis", description="Propagation axis for the EME simulation." ) - mode_specs: List[EMEModeSpec] = pd.Field( + mode_specs: list[EMEModeSpec] = pd.Field( ..., title="Mode Specifications", description="Mode specifications for the EME cells." ) @@ -744,7 +742,7 @@ def centers(self) -> Coords1D: return centers @property - def lengths(self) -> List[pd.NonNegativeFloat]: + def lengths(self) -> list[pd.NonNegativeFloat]: """Lengths of the EME cells along the propagation axis.""" rmin = self.boundaries[0] lengths = [] @@ -760,7 +758,7 @@ def num_cells(self) -> pd.NonNegativeInteger: return len(self.centers) @property - def mode_planes(self) -> List[Box]: + def mode_planes(self) -> list[Box]: """Planes for mode solving, aligned with cell centers.""" size = [inf, inf, inf] center = list(self.center) @@ -773,7 +771,7 @@ def mode_planes(self) -> List[Box]: return mode_planes @property - def boundary_planes(self) -> List[Box]: + def boundary_planes(self) -> list[Box]: """Planes aligned with cell boundaries.""" size = list(self.size) center = list(self.center) @@ -786,7 +784,7 @@ def boundary_planes(self) -> List[Box]: return boundary_planes @property - def cells(self) -> List[Box]: + def cells(self) -> list[Box]: """EME cells in the grid. Each cell is a :class:`.Box`.""" size = list(self.size) center = list(self.center) @@ -798,7 +796,7 @@ def cells(self) -> List[Box]: cells.append(Box(center=center, size=size)) return cells - def cell_indices_in_box(self, box: Box) -> List[pd.NonNegativeInteger]: + def cell_indices_in_box(self, box: Box) -> list[pd.NonNegativeInteger]: """Indices of cells that overlap with 'box'. Used to determine which data is recorded by a monitor. diff --git a/tidy3d/components/eme/monitor.py b/tidy3d/components/eme/monitor.py index aad5e5eb7f..4ee4e9e4d4 100644 --- a/tidy3d/components/eme/monitor.py +++ b/tidy3d/components/eme/monitor.py @@ -3,13 +3,13 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Literal, Optional, Tuple, Union +from typing import Literal, Optional, Union import pydantic.v1 as pd -from ..base_sim.monitor import AbstractMonitor -from ..monitor import AbstractFieldMonitor, ModeSolverMonitor, PermittivityMonitor -from ..types import FreqArray +from tidy3d.components.base_sim.monitor import AbstractMonitor +from tidy3d.components.monitor import AbstractFieldMonitor, ModeSolverMonitor, PermittivityMonitor +from tidy3d.components.types import FreqArray BYTES_COMPLEX = 8 @@ -42,7 +42,7 @@ class EMEMonitor(AbstractMonitor, ABC): "will be omitted. A value of 'None' will record all sweep indices.", ) - interval_space: Tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( + interval_space: tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( (1, 1, 1), title="Spatial Interval", description="Number of grid step intervals between monitor recordings. If equal to 1, " @@ -124,7 +124,7 @@ class EMEModeSolverMonitor(EMEMonitor): ... ) """ - interval_space: Tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( + interval_space: tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( (1, 1, 1), title="Spatial Interval", description="Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, " @@ -198,10 +198,10 @@ class EMEFieldMonitor(EMEMonitor, AbstractFieldMonitor): ... ) """ - interval_space: Tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( + interval_space: tuple[pd.PositiveInt, pd.PositiveInt, pd.PositiveInt] = pd.Field( (1, 1, 1), title="Spatial Interval", - description="Note: not yet supported. Number of grid step intervals between monitor recordings. If equal to 1, " + description="Number of grid step intervals between monitor recordings. If equal to 1, " "there will be no downsampling. If greater than 1, the step will be applied, but the " "first and last point of the monitor grid are always included.", ) @@ -262,7 +262,7 @@ class EMECoefficientMonitor(EMEMonitor): ... ) """ - interval_space: Tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( + interval_space: tuple[Literal[1], Literal[1], Literal[1]] = pd.Field( (1, 1, 1), title="Spatial Interval", description="Number of grid step intervals between monitor recordings. If equal to 1, " diff --git a/tidy3d/components/eme/simulation.py b/tidy3d/components/eme/simulation.py index a624ad9024..455ec221c8 100644 --- a/tidy3d/components/eme/simulation.py +++ b/tidy3d/components/eme/simulation.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Literal, Optional, Tuple, Union +from typing import Literal, Optional, Union try: import matplotlib as mpl @@ -11,25 +11,26 @@ import numpy as np import pydantic.v1 as pd -from ...constants import C_0 -from ...exceptions import SetupError, ValidationError -from ...log import log -from ..base import cached_property -from ..boundary import BoundarySpec, PECBoundary -from ..geometry.base import Box -from ..grid.grid import Grid -from ..grid.grid_spec import GridSpec -from ..medium import FullyAnisotropicMedium -from ..monitor import AbstractModeMonitor, ModeSolverMonitor, Monitor, MonitorType -from ..scene import Scene -from ..simulation import AbstractYeeGridSimulation, Simulation, validate_boundaries_for_zero_dims -from ..types import Ax, Axis, FreqArray, Symmetry, annotate_type -from ..validators import ( - MIN_FREQUENCY, - validate_freqs_min, - validate_freqs_not_empty, +from tidy3d.components.base import cached_property +from tidy3d.components.boundary import BoundarySpec, PECBoundary +from tidy3d.components.geometry.base import Box +from tidy3d.components.grid.grid import Grid +from tidy3d.components.grid.grid_spec import GridSpec +from tidy3d.components.medium import FullyAnisotropicMedium +from tidy3d.components.monitor import AbstractModeMonitor, ModeSolverMonitor, Monitor, MonitorType +from tidy3d.components.scene import Scene +from tidy3d.components.simulation import ( + AbstractYeeGridSimulation, + Simulation, + validate_boundaries_for_zero_dims, ) -from ..viz import add_ax_if_none, equal_aspect +from tidy3d.components.types import Ax, Axis, FreqArray, Symmetry, annotate_type +from tidy3d.components.validators import MIN_FREQUENCY, validate_freqs_min, validate_freqs_not_empty +from tidy3d.components.viz import add_ax_if_none, equal_aspect +from tidy3d.constants import C_0, inf +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .grid import EMECompositeGrid, EMEExplicitGrid, EMEGrid, EMEGridSpec, EMEGridSpecType from .monitor import ( EMECoefficientMonitor, @@ -181,7 +182,7 @@ class EMESimulation(AbstractYeeGridSimulation): "tangential directions, as well as the grid used for field monitors.", ) - monitors: Tuple[annotate_type(EMEMonitorType), ...] = pd.Field( + monitors: tuple[annotate_type(EMEMonitorType), ...] = pd.Field( (), title="Monitors", description="Tuple of monitors in the simulation. " @@ -199,7 +200,7 @@ class EMESimulation(AbstractYeeGridSimulation): "apply PML layers in the mode solver.", ) - sources: Tuple[None, ...] = pd.Field( + sources: tuple[None, ...] = pd.Field( (), title="Sources", description="Sources in the simulation. NOTE: sources are not currently supported " @@ -231,7 +232,7 @@ class EMESimulation(AbstractYeeGridSimulation): "thereby normalizing the scattering matrix and expansion coefficients.", ) - port_offsets: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + port_offsets: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( (0, 0), title="Port Offsets", description="Offsets for the two ports, relative to the simulation bounds " @@ -299,12 +300,12 @@ def _validate_structures(cls, val): @add_ax_if_none def plot_eme_ports( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **kwargs, ) -> Ax: """Plot the EME ports.""" @@ -343,12 +344,12 @@ def plot_eme_ports( def plot_eme_subgrid_boundaries( self, eme_grid_spec: EMEGridSpec, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **kwargs, ) -> Ax: """Plot the EME subgrid boundaries. @@ -395,12 +396,12 @@ def plot_eme_subgrid_boundaries( @add_ax_if_none def plot_eme_grid( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **kwargs, ) -> Ax: """Plot the EME grid.""" @@ -436,14 +437,14 @@ def plot_eme_grid( @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - source_alpha: float = None, - monitor_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **patch_kwargs, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -536,7 +537,7 @@ def from_scene(cls, scene: Scene, **kwargs) -> EMESimulation: ) @property - def mode_solver_monitors(self) -> List[ModeSolverMonitor]: + def mode_solver_monitors(self) -> list[ModeSolverMonitor]: """A list of mode solver monitors at the cell centers. Each monitor has a mode spec. The cells and mode specs are specified by 'eme_grid_spec'.""" @@ -559,9 +560,11 @@ def mode_solver_monitors(self) -> List[ModeSolverMonitor]: @property def port_modes_monitor(self) -> EMEModeSolverMonitor: """EME Mode solver monitor for only the port modes.""" + size = [inf, inf, inf] + size[self.axis] = self.size[self.axis] return EMEModeSolverMonitor( center=self.center, - size=self.size, + size=size, eme_cell_interval_space=self.eme_grid.num_cells, name="_eme_port_modes_monitor", colocate=False, @@ -692,8 +695,7 @@ def _validate_sweep_spec(self): scale_factors_shape = self.sweep_spec.scale_factors.shape if len(scale_factors_shape) > 2: raise SetupError( - "Simulation 'sweep_spec.scale_factors' must " - "have either one or two dimensions." + "Simulation 'sweep_spec.scale_factors' must have either one or two dimensions." ) if len(scale_factors_shape) == 2: num_scale_factors = scale_factors_shape[1] @@ -720,7 +722,7 @@ def _validate_sweep_spec(self): f"Monitor at 'monitors[{i}]' is an 'EMEFieldMonitor', " "which is not compatible with 'EMEPeriodicitySweep'." ) - elif isinstance(monitor, EMECoefficientMonitor): + if isinstance(monitor, EMECoefficientMonitor): raise SetupError( f"Monitor at 'monitors[{i}]' is an 'EMECoefficientMonitor', " "which is not compatible with 'EMEPeriodicitySweep'." @@ -856,7 +858,7 @@ def _validate_monitor_size(self) -> None: def _validate_modes_size(self) -> None: """Warn if mode sources or monitors have a large number of points.""" - def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: List): + def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list): """Warn if a mode component has a large number of points.""" num_cells = np.prod(self.discretize_monitor(monitor).num_cells) if num_cells > WARN_MODE_NUM_CELLS: @@ -880,14 +882,14 @@ def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: Li warn_mode_size(monitor=monitor, msg_header=msg_header, custom_loc=custom_loc) @property - def _monitors_full(self) -> Tuple[EMEMonitorType, ...]: + def _monitors_full(self) -> tuple[EMEMonitorType, ...]: """All monitors, including port modes monitor.""" if self.store_port_modes: - return list(self.monitors) + [self.port_modes_monitor] + return [*list(self.monitors), self.port_modes_monitor] return list(self.monitors) @cached_property - def monitors_data_size(self) -> Dict[str, float]: + def monitors_data_size(self) -> dict[str, float]: """Dictionary mapping monitor names to their estimated storage size in bytes.""" data_size = {} for monitor in self._monitors_full: @@ -971,7 +973,7 @@ def _monitor_num_sweep(self, monitor: EMEMonitor) -> pd.PositiveInt: return self.sweep_spec.num_sweep return min(self.sweep_spec.num_sweep, monitor.num_sweep) - def _monitor_eme_cell_indices(self, monitor: EMEMonitor) -> List[pd.NonNegativeInt]: + def _monitor_eme_cell_indices(self, monitor: EMEMonitor) -> list[pd.NonNegativeInt]: """EME cell indices inside monitor. Takes into account 'eme_cell_interval_space'.""" cell_indices_full = self.eme_grid.cell_indices_in_box(box=monitor.geometry) if len(cell_indices_full) == 0: @@ -986,7 +988,7 @@ def _monitor_num_eme_cells(self, monitor: EMEMonitor) -> int: """Total number of EME cells included in monitor based on simulation grid.""" return len(self._monitor_eme_cell_indices(monitor=monitor)) - def _monitor_freqs(self, monitor: Monitor) -> List[pd.NonNegativeFloat]: + def _monitor_freqs(self, monitor: Monitor) -> list[pd.NonNegativeFloat]: """Monitor frequencies.""" if monitor.freqs is None: return list(self.freqs) @@ -1094,8 +1096,9 @@ def subsection( region: Box, grid_spec: Union[GridSpec, Literal["identical"]] = None, eme_grid_spec: Union[EMEGridSpec, Literal["identical"]] = None, - symmetry: Tuple[Symmetry, Symmetry, Symmetry] = None, - monitors: Tuple[MonitorType, ...] = None, + symmetry: Optional[tuple[Symmetry, Symmetry, Symmetry]] = None, + warn_symmetry_expansion: bool = True, + monitors: Optional[tuple[MonitorType, ...]] = None, remove_outside_structures: bool = True, remove_outside_custom_mediums: bool = False, **kwargs, @@ -1121,6 +1124,8 @@ def subsection( New simulation symmetry. If ``None``, then it is inherited from the original simulation. Note that in this case the size and placement of new simulation domain must be commensurate with the original symmetry. + warn_symmetry_expansion : bool = True + Whether to warn when the subsection is expanded to preserve symmetry. monitors : Tuple[MonitorType, ...] = None New list of monitors. If ``None``, then the monitors intersecting the new simulation domain are inherited from the original simulation. @@ -1158,7 +1163,7 @@ def subsection( new_sim = super().subsection( region=new_region, grid_spec=grid_spec, - symmetry=symmetry, + warn_symmetry_expansion=warn_symmetry_expansion, monitors=monitors, remove_outside_structures=remove_outside_structures, remove_outside_custom_mediums=remove_outside_custom_mediums, @@ -1170,7 +1175,7 @@ def subsection( return new_sim @property - def _cell_index_pairs(self) -> List[pd.NonNegativeInt]: + def _cell_index_pairs(self) -> list[pd.NonNegativeInt]: """All the pairs of adjacent EME cells needed, taken over all sweep indices.""" pairs = set() if isinstance(self.sweep_spec, EMEPeriodicitySweep): @@ -1181,4 +1186,4 @@ def _cell_index_pairs(self) -> List[pd.NonNegativeInt]: pairs = set(self.eme_grid_spec._cell_index_pairs) return list(pairs) - _boundaries_for_zero_dims = validate_boundaries_for_zero_dims() + _boundaries_for_zero_dims = validate_boundaries_for_zero_dims(warn_on_change=False) diff --git a/tidy3d/components/eme/sweep.py b/tidy3d/components/eme/sweep.py index d4130e00f3..6ded35c645 100644 --- a/tidy3d/components/eme/sweep.py +++ b/tidy3d/components/eme/sweep.py @@ -3,13 +3,14 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Dict, List, Union +from typing import Union import pydantic.v1 as pd -from ...exceptions import SetupError -from ..base import Tidy3dBaseModel -from ..types import ArrayFloat1D, ArrayInt1D, ArrayLike +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.types import ArrayFloat1D, ArrayInt1D, ArrayLike +from tidy3d.exceptions import SetupError + from .grid import MAX_NUM_REPS @@ -99,7 +100,7 @@ class EMEPeriodicitySweep(EMESweepSpec): >>> sweep_spec = EMEPeriodicitySweep(num_reps=[{"unit_cell": n} for n in n_list]) """ - num_reps: List[Dict[str, pd.PositiveInt]] = pd.Field( + num_reps: list[dict[str, pd.PositiveInt]] = pd.Field( ..., title="Number of Repetitions", description="Number of periodic repetitions of named subgrids in this EME grid. " diff --git a/tidy3d/components/field_projection.py b/tidy3d/components/field_projection.py index b66e14484a..4346a85d50 100644 --- a/tidy3d/components/field_projection.py +++ b/tidy3d/components/field_projection.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Iterable, List, Tuple, Union +from collections.abc import Iterable +from typing import Union import autograd.numpy as anp import numpy as np @@ -10,9 +11,10 @@ import xarray as xr from rich.progress import track -from ..constants import C_0, EPSILON_0, ETA_0, MICROMETER, MU_0 -from ..exceptions import SetupError -from ..log import get_logging_console +from tidy3d.constants import C_0, EPSILON_0, ETA_0, MICROMETER, MU_0 +from tidy3d.exceptions import SetupError +from tidy3d.log import get_logging_console + from .autograd.functions import add_at, trapz from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing from .data.data_array import ( @@ -44,7 +46,7 @@ # Numpy float array and related array types -ArrayLikeN2F = Union[float, Tuple[float, ...], ArrayComplex4D] +ArrayLikeN2F = Union[float, tuple[float, ...], ArrayComplex4D] class FieldProjector(Tidy3dBaseModel): @@ -70,7 +72,7 @@ class FieldProjector(Tidy3dBaseModel): description="Container for simulation data containing the near field monitors.", ) - surfaces: Tuple[FieldProjectionSurface, ...] = pydantic.Field( + surfaces: tuple[FieldProjectionSurface, ...] = pydantic.Field( ..., title="Surface monitor with direction", description="Tuple of each :class:`.FieldProjectionSurface` to use as source of " @@ -116,7 +118,7 @@ def medium(self) -> MediumType: return sim.monitor_medium(monitor) @cached_property - def frequencies(self) -> List[float]: + def frequencies(self) -> list[float]: """Return the list of frequencies associated with the field monitors.""" return self.surfaces[0].monitor.freqs @@ -124,8 +126,8 @@ def frequencies(self) -> List[float]: def from_near_field_monitors( cls, sim_data: SimulationData, - near_monitors: List[FieldMonitor], - normal_dirs: List[Direction], + near_monitors: list[FieldMonitor], + normal_dirs: list[Direction], pts_per_wavelength: int = PTS_PER_WVL, origin: Coordinate = None, ): @@ -268,7 +270,7 @@ def _fields_to_currents(field_data: FieldData, surface: FieldProjectionSurface) surface_currents[H2] = field_data.field_components[E1] * signs[0] surface_currents[H1] = field_data.field_components[E2] * signs[1] - new_monitor = surface.monitor.copy(update=dict(fields=[E1, E2, H1, H2])) + new_monitor = surface.monitor.copy(update={"fields": [E1, E2, H1, H2]}) return FieldData( monitor=new_monitor, @@ -905,7 +907,7 @@ def _fields_for_surface_exact( d2G_dr2 = dG_dr * (ikr - 1.0) / r + G / (r**2) # operations between unit vectors and currents - def r_x_current(current: Tuple[np.ndarray, ...]) -> Tuple[np.ndarray, ...]: + def r_x_current(current: tuple[np.ndarray, ...]) -> tuple[np.ndarray, ...]: """Cross product between the r unit vector and the current.""" return [ sin_theta * sin_phi * current[2] - cos_theta * current[1], @@ -913,7 +915,7 @@ def r_x_current(current: Tuple[np.ndarray, ...]) -> Tuple[np.ndarray, ...]: sin_theta * cos_phi * current[1] - sin_theta * sin_phi * current[0], ] - def r_dot_current(current: Tuple[np.ndarray, ...]) -> np.ndarray: + def r_dot_current(current: tuple[np.ndarray, ...]) -> np.ndarray: """Dot product between the r unit vector and the current.""" return ( sin_theta * cos_phi * current[0] @@ -921,7 +923,7 @@ def r_dot_current(current: Tuple[np.ndarray, ...]) -> np.ndarray: + cos_theta * current[2] ) - def r_dot_current_dtheta(current: Tuple[np.ndarray, ...]) -> np.ndarray: + def r_dot_current_dtheta(current: tuple[np.ndarray, ...]) -> np.ndarray: """Theta derivative of the dot product between the r unit vector and the current.""" return ( cos_theta * cos_phi * current[0] @@ -929,12 +931,12 @@ def r_dot_current_dtheta(current: Tuple[np.ndarray, ...]) -> np.ndarray: - sin_theta * current[2] ) - def r_dot_current_dphi_div_sin_theta(current: Tuple[np.ndarray, ...]) -> np.ndarray: + def r_dot_current_dphi_div_sin_theta(current: tuple[np.ndarray, ...]) -> np.ndarray: """Phi derivative of the dot product between the r unit vector and the current, analytically divided by sin theta.""" return -sin_phi * current[0] + cos_phi * current[1] - def grad_Gr_r_dot_current(current: Tuple[np.ndarray, ...]) -> Tuple[np.ndarray, ...]: + def grad_Gr_r_dot_current(current: tuple[np.ndarray, ...]) -> tuple[np.ndarray, ...]: """Gradient of the product of the gradient of the Green's function and the dot product between the r unit vector and the current.""" temp = [ @@ -945,7 +947,7 @@ def grad_Gr_r_dot_current(current: Tuple[np.ndarray, ...]) -> Tuple[np.ndarray, # convert to Cartesian coordinates return surface.monitor.sph_2_car_field(temp[0], temp[1], temp[2], theta_obs, phi_obs) - def potential_terms(current: Tuple[np.ndarray, ...], const: complex): + def potential_terms(current: tuple[np.ndarray, ...], const: complex): """Assemble vector potential and its derivatives.""" r_x_c = r_x_current(current) pot = [const * item * G for item in current] diff --git a/tidy3d/components/file_util.py b/tidy3d/components/file_util.py index b530baddcd..c57fb15322 100644 --- a/tidy3d/components/file_util.py +++ b/tidy3d/components/file_util.py @@ -1,5 +1,7 @@ """File compression utilities""" +from __future__ import annotations + import gzip import shutil from typing import Any @@ -58,7 +60,7 @@ def replace_values(values: Any, search_value: Any, replace_value: Any) -> Any: return { key: replace_values(val, search_value, replace_value) for key, val in values.items() } - elif isinstance( + if isinstance( values, (tuple, list) ): # Parts of the nested dict structure include tuples with more dicts return type(values)(replace_values(val, search_value, replace_value) for val in values) diff --git a/tidy3d/components/frequencies.py b/tidy3d/components/frequencies.py index 6a14fb5b6b..810558ac62 100644 --- a/tidy3d/components/frequencies.py +++ b/tidy3d/components/frequencies.py @@ -1,9 +1,12 @@ """Frequency utilities.""" +from __future__ import annotations + import numpy as np import pydantic as pd -from ..constants import C_0 +from tidy3d.constants import C_0 + from .base import Tidy3dBaseModel O_BAND = (1.260, 1.360) @@ -44,54 +47,54 @@ def classification(self, value: float) -> tuple[str]: value = C_0 / value if value < 3: return ("near static",) - elif value < 300e6: + if value < 300e6: if value < 30: return ("radio wave", "ELF") - elif value < 300: + if value < 300: return ("radio wave", "SLF") - elif value < 3e3: + if value < 3e3: return ("radio wave", "ULF") - elif value < 30e3: + if value < 30e3: return ("radio wave", "VLF") - elif value < 300e3: + if value < 300e3: return ("radio wave", "LF") - elif value < 3e6: + if value < 3e6: return ("radio wave", "MF") - elif value < 30e6: + if value < 30e6: return ("radio wave", "HF") return ("radio wave", "VHF") - elif value < 300e9: + if value < 300e9: if value < 3e9: return ("microwave", "UHF") - elif value < 30e9: + if value < 30e9: return ("microwave", "SHF") return ("microwave", "EHF") - elif value < 400e12: + if value < 400e12: if value < 6e12: return ("infrared", "FIR") - elif value < 100e12: + if value < 100e12: return ("infrared", "MIR") return ("infrared", "NIR") - elif value < 790e12: + if value < 790e12: if value < 480e12: return ("visible", "red") - elif value < 510e12: + if value < 510e12: return ("visible", "orange") - elif value < 530e12: + if value < 530e12: return ("visible", "yellow") - elif value < 600e12: + if value < 600e12: return ("visible", "green") - elif value < 620e12: + if value < 620e12: return ("visible", "cyan") - elif value < 670e12: + if value < 670e12: return ("visible", "blue") return ("visible", "violet") - elif value < 30e15: + if value < 30e15: if value < 1e15: return ("ultraviolet", "NUV") - elif value < 1.5e15: + if value < 1.5e15: return ("ultraviolet", "MUV") - elif value < 2.47e15: + if value < 2.47e15: return ("ultraviolet", "FUV") return ("ultraviolet", "EUV") if value < 30e18: diff --git a/tidy3d/components/geometry/base.py b/tidy3d/components/geometry/base.py index 9fddfddc72..7157a79d5a 100644 --- a/tidy3d/components/geometry/base.py +++ b/tidy3d/components/geometry/base.py @@ -5,7 +5,7 @@ import functools import pathlib from abc import ABC, abstractmethod -from typing import Any, Callable, List, Tuple, Union +from typing import Any, Callable, Optional, Union import autograd.numpy as np import pydantic.v1 as pydantic @@ -17,21 +17,13 @@ except ImportError: pass -from ...constants import LARGE_NUMBER, MICROMETER, RADIAN, fp_eps, inf -from ...exceptions import ( - SetupError, - Tidy3dError, - Tidy3dImportError, - Tidy3dKeyError, - ValidationError, -) -from ...log import log -from ...packaging import check_import, verify_packages_import -from ..autograd import AutogradFieldMap, TracedCoordinate, TracedSize, get_static -from ..autograd.derivative_utils import DerivativeInfo, integrate_within_bounds -from ..base import Tidy3dBaseModel, cached_property -from ..transformation import ReflectionFromPlane, RotationAroundAxis -from ..types import ( +from tidy3d.compat import _shapely_is_older_than +from tidy3d.components.autograd import AutogradFieldMap, TracedCoordinate, TracedSize, get_static +from tidy3d.components.autograd.constants import GRADIENT_DTYPE_FLOAT +from tidy3d.components.autograd.derivative_utils import DerivativeInfo, integrate_within_bounds +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.transformation import ReflectionFromPlane, RotationAroundAxis +from tidy3d.components.types import ( ArrayFloat2D, ArrayFloat3D, Ax, @@ -47,7 +39,7 @@ Size, annotate_type, ) -from ..viz import ( +from tidy3d.components.viz import ( ARROW_LENGTH, PLOT_BUFFER, PlotParams, @@ -59,8 +51,21 @@ polygon_patch, set_default_labels_and_title, ) +from tidy3d.constants import LARGE_NUMBER, MICROMETER, RADIAN, fp_eps, inf +from tidy3d.exceptions import ( + SetupError, + Tidy3dError, + Tidy3dImportError, + Tidy3dKeyError, + ValidationError, +) +from tidy3d.log import log +from tidy3d.packaging import verify_packages_import + +from .bound_ops import bounds_intersection, bounds_union POLY_GRID_SIZE = 1e-12 +POLY_TOLERANCE_RATIO = 1e-12 _shapely_operations = { @@ -151,7 +156,7 @@ def make_shapely_point(minx: float, miny: float) -> shapely.Point: def _inds_inside_bounds( self, x: np.ndarray[float], y: np.ndarray[float], z: np.ndarray[float] - ) -> Tuple[slice, slice, slice]: + ) -> tuple[slice, slice, slice]: """Return slices into the sorted input arrays that are inside the geometry bounds. Parameters @@ -213,7 +218,7 @@ def inside_meshgrid( @abstractmethod def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -234,8 +239,8 @@ def intersections_tilted_plane( """ def intersections_plane( - self, x: float = None, y: float = None, z: float = None - ) -> List[Shapely]: + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ) -> list[Shapely]: """Returns list of shapely geometries at plane specified by one non-None value of x,y,z. Parameters @@ -260,10 +265,10 @@ def intersections_plane( to_2D = np.eye(4) if axis != 2: last, indices = self.pop_axis((0, 1, 2), axis) - to_2D = to_2D[list(indices) + [last, 3]] + to_2D = to_2D[[*list(indices), last, 3]] return self.intersections_tilted_plane(normal, origin, to_2D) - def intersections_2dbox(self, plane: Box) -> List[Shapely]: + def intersections_2dbox(self, plane: Box) -> list[Shapely]: """Returns list of shapely geometries representing the intersections of the geometry with a 2D box. @@ -280,7 +285,7 @@ def intersections_2dbox(self, plane: Box) -> List[Shapely]: return plane.intersections_with(self) def intersects( - self, other, strict_inequality: Tuple[bool, bool, bool] = [False, False, False] + self, other, strict_inequality: tuple[bool, bool, bool] = [False, False, False] ) -> bool: """Returns ``True`` if two :class:`Geometry` have intersecting `.bounds`. @@ -318,7 +323,7 @@ def intersects( return True def contains( - self, other: Geometry, strict_inequality: Tuple[bool, bool, bool] = [False, False, False] + self, other: Geometry, strict_inequality: tuple[bool, bool, bool] = [False, False, False] ) -> bool: """Returns ``True`` if the `.bounds` of ``other`` are contained within the `.bounds` of ``self``. @@ -356,7 +361,9 @@ def contains( return True - def intersects_plane(self, x: float = None, y: float = None, z: float = None) -> bool: + def intersects_plane( + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ) -> bool: """Whether self intersects plane specified by one non-None value of x,y,z. Parameters @@ -408,20 +415,12 @@ def bounds(self) -> Bound: @staticmethod def bounds_intersection(bounds1: Bound, bounds2: Bound) -> Bound: """Return the bounds that are the intersection of two bounds.""" - rmin1, rmax1 = bounds1 - rmin2, rmax2 = bounds2 - rmin = tuple(max(v1, v2) for v1, v2 in zip(rmin1, rmin2)) - rmax = tuple(min(v1, v2) for v1, v2 in zip(rmax1, rmax2)) - return (rmin, rmax) + return bounds_intersection(bounds1, bounds2) @staticmethod def bounds_union(bounds1: Bound, bounds2: Bound) -> Bound: """Return the bounds that are the union of two bounds.""" - rmin1, rmax1 = bounds1 - rmin2, rmax2 = bounds2 - rmin = tuple(min(v1, v2) for v1, v2 in zip(rmin1, rmin2)) - rmax = tuple(max(v1, v2) for v1, v2 in zip(rmax1, rmax2)) - return (rmin, rmax) + return bounds_union(bounds1, bounds2) @cached_property def bounding_box(self): @@ -435,7 +434,7 @@ def bounding_box(self): return Box.from_bounds(*self.bounds) @cached_property - def zero_dims(self) -> List[Axis]: + def zero_dims(self) -> list[Axis]: """A list of axes along which the :class:`Geometry` is zero-sized based on its bounds.""" zero_dims = [] for dim in range(3): @@ -443,7 +442,7 @@ def zero_dims(self) -> List[Axis]: zero_dims.append(dim) return zero_dims - def _pop_bounds(self, axis: Axis) -> Tuple[Coordinate2D, Tuple[Coordinate2D, Coordinate2D]]: + def _pop_bounds(self, axis: Axis) -> tuple[Coordinate2D, tuple[Coordinate2D, Coordinate2D]]: """Returns min and max bounds in plane normal to and tangential to ``axis``. Parameters @@ -483,7 +482,7 @@ def _normal_2dmaterial(self) -> Axis: """Get the normal to the given geometry, checking that it is a 2D geometry.""" raise ValidationError("'Medium2D' is not compatible with this geometry class.") - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Geometry: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> Geometry: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" raise NotImplementedError( @@ -494,9 +493,9 @@ def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Geomet @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, plot_length_units: LengthUnit = None, viz_spec: VisualizationSpec = None, @@ -594,7 +593,7 @@ def _do_not_intersect(bounds_a, bounds_b, shape_a, shape_b): return False @staticmethod - def _get_plot_labels(axis: Axis) -> Tuple[str, str]: + def _get_plot_labels(axis: Axis) -> tuple[str, str]: """Returns planar coordinate x and y axis labels for cross section plots. Parameters @@ -612,7 +611,7 @@ def _get_plot_labels(axis: Axis) -> Tuple[str, str]: def _get_plot_limits( self, axis: Axis, buffer: float = PLOT_BUFFER - ) -> Tuple[Coordinate2D, Coordinate2D]: + ) -> tuple[Coordinate2D, Coordinate2D]: """Gets planar coordinate limits for cross section plots. Parameters @@ -659,9 +658,9 @@ def add_ax_lims(self, axis: Axis, ax: Ax, buffer: float = PLOT_BUFFER) -> Ax: @staticmethod def add_ax_labels_and_title( ax: Ax, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, plot_length_units: LengthUnit = None, ) -> Ax: """Sets the axis labels, tick labels, and title based on ``axis`` @@ -726,7 +725,7 @@ def evaluate_inf_shape(shape: Shapely) -> Shapely: return shape @staticmethod - def pop_axis(coord: Tuple[Any, Any, Any], axis: int) -> Tuple[Any, Tuple[Any, Any]]: + def pop_axis(coord: tuple[Any, Any, Any], axis: int) -> tuple[Any, tuple[Any, Any]]: """Separates coordinate at ``axis`` index from coordinates on the plane tangent to ``axis``. Parameters @@ -748,7 +747,7 @@ def pop_axis(coord: Tuple[Any, Any, Any], axis: int) -> Tuple[Any, Tuple[Any, An return axis_val, tuple(plane_vals) @staticmethod - def unpop_axis(ax_coord: Any, plane_coords: Tuple[Any, Any], axis: int) -> Tuple[Any, Any, Any]: + def unpop_axis(ax_coord: Any, plane_coords: tuple[Any, Any], axis: int) -> tuple[Any, Any, Any]: """Combine coordinate along axis with coordinates on the plane tangent to the axis. Parameters @@ -770,7 +769,7 @@ def unpop_axis(ax_coord: Any, plane_coords: Tuple[Any, Any], axis: int) -> Tuple return tuple(coords) @staticmethod - def parse_xyz_kwargs(**xyz) -> Tuple[Axis, float]: + def parse_xyz_kwargs(**xyz) -> tuple[Axis, float]: """Turns x,y,z kwargs into index of the normal axis and position along that axis. Parameters @@ -795,7 +794,7 @@ def parse_xyz_kwargs(**xyz) -> Tuple[Axis, float]: return axis, position @staticmethod - def parse_two_xyz_kwargs(**xyz) -> List[Tuple[Axis, float]]: + def parse_two_xyz_kwargs(**xyz) -> list[tuple[Axis, float]]: """Turns x,y,z kwargs into indices of axes and the position along each axis. Parameters @@ -994,7 +993,7 @@ def reflected(self, normal: Coordinate) -> Geometry: """ Field and coordinate transformations """ @staticmethod - def car_2_sph(x: float, y: float, z: float) -> Tuple[float, float, float]: + def car_2_sph(x: float, y: float, z: float) -> tuple[float, float, float]: """Convert Cartesian to spherical coordinates. Parameters @@ -1017,7 +1016,7 @@ def car_2_sph(x: float, y: float, z: float) -> Tuple[float, float, float]: return r, theta, phi @staticmethod - def sph_2_car(r: float, theta: float, phi: float) -> Tuple[float, float, float]: + def sph_2_car(r: float, theta: float, phi: float) -> tuple[float, float, float]: """Convert spherical to Cartesian coordinates. Parameters @@ -1043,7 +1042,7 @@ def sph_2_car(r: float, theta: float, phi: float) -> Tuple[float, float, float]: @staticmethod def sph_2_car_field( f_r: float, f_theta: float, f_phi: float, theta: float, phi: float - ) -> Tuple[complex, complex, complex]: + ) -> tuple[complex, complex, complex]: """Convert vector field components in spherical coordinates to cartesian. Parameters @@ -1076,7 +1075,7 @@ def sph_2_car_field( @staticmethod def car_2_sph_field( f_x: float, f_y: float, f_z: float, theta: float, phi: float - ) -> Tuple[complex, complex, complex]: + ) -> tuple[complex, complex, complex]: """Convert vector field components in cartesian coordinates to spherical. Parameters @@ -1108,7 +1107,7 @@ def car_2_sph_field( return f_r, f_theta, f_phi @staticmethod - def kspace_2_sph(ux: float, uy: float, axis: Axis) -> Tuple[float, float]: + def kspace_2_sph(ux: float, uy: float, axis: Axis) -> tuple[float, float]: """Convert normalized k-space coordinates to angles. Parameters @@ -1145,16 +1144,19 @@ def kspace_2_sph(ux: float, uy: float, axis: Axis) -> Tuple[float, float]: return theta, phi @staticmethod - @verify_packages_import(["gdstk", "gdspy"], required="any") + @verify_packages_import(["gdstk"]) def load_gds_vertices_gdstk( - gds_cell, gds_layer: int, gds_dtype: int = None, gds_scale: pydantic.PositiveFloat = 1.0 - ) -> List[ArrayFloat2D]: + gds_cell, + gds_layer: int, + gds_dtype: Optional[int] = None, + gds_scale: pydantic.PositiveFloat = 1.0, + ) -> list[ArrayFloat2D]: """Load polygon vertices from a ``gdstk.Cell``. Parameters ---------- gds_cell : gdstk.Cell - ``gdstk.Cell`` or ``gdspy.Cell`` containing 2D geometric data. + ``gdstk.Cell`` containing 2D geometric data. gds_layer : int Layer index in the ``gds_cell``. gds_dtype : int = None @@ -1194,67 +1196,24 @@ def load_gds_vertices_gdstk( return all_vertices @staticmethod - @verify_packages_import(["gdstk", "gdspy"], required="any") - def load_gds_vertices_gdspy( - gds_cell, gds_layer: int, gds_dtype: int = None, gds_scale: pydantic.PositiveFloat = 1.0 - ) -> List[ArrayFloat2D]: - """Load polygon vertices from a ``gdspy.Cell``. - - Parameters - ---------- - gds_cell : gdspy.Cell - ``gdstk.Cell`` or ``gdspy.Cell`` containing 2D geometric data. - gds_layer : int - Layer index in the ``gds_cell``. - gds_dtype : int = None - Data-type index in the ``gds_cell``. If ``None``, imports all data for this layer into - the returned list. - gds_scale : float = 1.0 - Length scale used in GDS file in units of micrometer. For example, if gds file uses - nanometers, set ``gds_scale=1e-3``. Must be positive. - - Returns - ------- - List[ArrayFloat2D] - List of polygon vertices - """ - - # load the polygon vertices - vert_dict = gds_cell.get_polygons(by_spec=True) - all_vertices = [] - for (gds_layer_file, gds_dtype_file), vertices in vert_dict.items(): - if gds_layer_file == gds_layer and (gds_dtype is None or gds_dtype == gds_dtype_file): - all_vertices.extend(iter(vertices)) - # make sure something got loaded, otherwise error - if not all_vertices: - raise Tidy3dKeyError( - f"Couldn't load gds_cell, no vertices found at gds_layer={gds_layer} " - f"with specified gds_dtype={gds_dtype}." - ) - - # apply scaling - all_vertices = [vertices * gds_scale for vertices in all_vertices] - return all_vertices - - @staticmethod - @verify_packages_import(["gdstk", "gdspy"], required="any") + @verify_packages_import(["gdstk"]) def from_gds( gds_cell, axis: Axis, - slab_bounds: Tuple[float, float], + slab_bounds: tuple[float, float], gds_layer: int, - gds_dtype: int = None, + gds_dtype: Optional[int] = None, gds_scale: pydantic.PositiveFloat = 1.0, dilation: float = 0.0, sidewall_angle: float = 0, reference_plane: PlanePosition = "middle", ) -> Geometry: - """Import a ``gdstk.Cell`` or a ``gdspy.Cell`` and extrude it into a GeometryGroup. + """Import a ``gdstk.Cell`` and extrude it into a GeometryGroup. Parameters ---------- - gds_cell : Union[gdstk.Cell, gdspy.Cell] - ``gdstk.Cell`` or ``gdspy.Cell`` containing 2D geometric data. + gds_cell : gdstk.Cell + ``gdstk.Cell`` containing 2D geometric data. axis : int Integer index defining the extrusion axis: 0 (x), 1 (y), or 2 (z). slab_bounds: Tuple[float, float] @@ -1283,32 +1242,18 @@ def from_gds( :class:`Geometry` Geometries created from the 2D data. """ - gdstk_available = check_import("gdstk") - gdspy_available = check_import("gdspy") - - if gdstk_available: - import gdstk - - if isinstance(gds_cell, gdstk.Cell): - gds_loader_fn = Geometry.load_gds_vertices_gdstk - elif gdspy_available: - import gdspy + import gdstk - if isinstance(gds_cell, gdspy.Cell): - gds_loader_fn = Geometry.load_gds_vertices_gdspy - elif "gdstk" in gds_cell.__class__ and not gdstk_available: - raise Tidy3dImportError( - "Module 'gdstk' not found. It is required to import gdstk cells." - ) - elif "gdspy" in gds_cell.__class__ and not gdspy_available: - raise Tidy3dImportError( - "Module 'gdspy' not found. It is required to import to gdspy cells." - ) - else: - raise Tidy3dError( - "Argument 'gds_cell' must be an instance of 'gdstk.Cell' or 'gdspy.Cell'." - ) + if not isinstance(gds_cell, gdstk.Cell): + # Check if it might be a gdstk cell but gdstk is not found (should be caught by decorator) + # or if it's an entirely different type. + if "gdstk" in gds_cell.__class__.__name__.lower(): + raise Tidy3dImportError( + "Module 'gdstk' not found. It is required to import gdstk cells." + ) + raise Tidy3dImportError("Argument 'gds_cell' must be an instance of 'gdstk.Cell'.") + gds_loader_fn = Geometry.load_gds_vertices_gdstk geometries = [] with log as consolidated_logger: for vertices in gds_loader_fn(gds_cell, gds_layer, gds_dtype, gds_scale): @@ -1330,7 +1275,7 @@ def from_gds( def from_shapely( shape: Shapely, axis: Axis, - slab_bounds: Tuple[float, float], + slab_bounds: tuple[float, float], dilation: float = 0.0, sidewall_angle: float = 0, reference_plane: PlanePosition = "middle", @@ -1368,12 +1313,12 @@ def from_shapely( @verify_packages_import(["gdstk"]) def to_gdstk( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, gds_layer: pydantic.NonNegativeInt = 0, gds_dtype: pydantic.NonNegativeInt = 0, - ) -> List: + ) -> list: """Convert a Geometry object's planar slice to a .gds type polygon. Parameters @@ -1414,62 +1359,13 @@ def to_gdstk( ) return polygons - @verify_packages_import(["gdspy"]) - def to_gdspy( - self, - x: float = None, - y: float = None, - z: float = None, - gds_layer: pydantic.NonNegativeInt = 0, - gds_dtype: pydantic.NonNegativeInt = 0, - ) -> List: - """Convert a Geometry object's planar slice to a .gds type polygon. - - Parameters - ---------- - x : float = None - Position of plane in x direction, only one of x,y,z can be specified to define plane. - y : float = None - Position of plane in y direction, only one of x,y,z can be specified to define plane. - z : float = None - Position of plane in z direction, only one of x,y,z can be specified to define plane. - gds_layer : int = 0 - Layer index to use for the shapes stored in the .gds file. - gds_dtype : int = 0 - Data-type index to use for the shapes stored in the .gds file. - - Return - ------ - List - List of `gdspy.Polygon` and `gdspy.PolygonSet`. - """ - import gdspy - - shapes = self.intersections_plane(x=x, y=y, z=z) - polygons = [] - for shape in shapes: - for vertices in vertices_from_shapely(shape): - if len(vertices) == 1: - polygons.append(gdspy.Polygon(vertices[0], gds_layer, gds_dtype)) - else: - polygons.append( - gdspy.boolean( - vertices[:1], - vertices[1:], - "not", - layer=gds_layer, - datatype=gds_dtype, - ) - ) - return polygons - - @verify_packages_import(["gdstk", "gdspy"], required="any") + @verify_packages_import(["gdstk"]) def to_gds( self, cell, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, gds_layer: pydantic.NonNegativeInt = 0, gds_dtype: pydantic.NonNegativeInt = 0, ) -> None: @@ -1477,7 +1373,7 @@ def to_gds( Parameters ---------- - cell : ``gdstk.Cell`` or ``gdspy.Cell`` + cell : ``gdstk.Cell`` Cell object to which the generated polygons are added. x : float = None Position of plane in x direction, only one of x,y,z can be specified to define plane. @@ -1490,45 +1386,26 @@ def to_gds( gds_dtype : int = 0 Data-type index to use for the shapes stored in the .gds file. """ - gdstk_available = check_import("gdstk") - gdspy_available = check_import("gdspy") - - if gdstk_available: - import gdstk - - if isinstance(cell, gdstk.Cell): - polygons = self.to_gdstk(x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) - if len(polygons) > 0: - cell.add(*polygons) - - elif gdspy_available: - import gdspy + import gdstk - if isinstance(cell, gdspy.Cell): - polygons = self.to_gdspy(x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) - if len(polygons) > 0: - cell.add(polygons) + if not isinstance(cell, gdstk.Cell): + if "gdstk" in cell.__class__.__name__.lower(): + raise Tidy3dImportError( + "Module 'gdstk' not found. It is required to export shapes to gdstk cells." + ) + raise Tidy3dImportError("Argument 'cell' must be an instance of 'gdstk.Cell'.") - elif "gdstk" in cell.__class__ and not gdstk_available: - raise Tidy3dImportError( - "Module 'gdstk' not found. It is required to export shapes to gdstk cells." - ) - elif "gdspy" in cell.__class__ and not gdspy_available: - raise Tidy3dImportError( - "Module 'gdspy' not found. It is required to export shapes to gdspy cells." - ) - else: - raise Tidy3dError( - "Argument 'cell' must be an instance of 'gdstk.Cell' or 'gdspy.Cell'." - ) + polygons = self.to_gdstk(x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) + if polygons: + cell.add(*polygons) - @verify_packages_import(["gdstk", "gdspy"], required="any") + @verify_packages_import(["gdstk"]) def to_gds_file( self, fname: str, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, gds_layer: pydantic.NonNegativeInt = 0, gds_dtype: pydantic.NonNegativeInt = 0, gds_cell_name: str = "MAIN", @@ -1552,35 +1429,25 @@ def to_gds_file( gds_cell_name : str = 'MAIN' Name of the cell created in the .gds file to store the geometry. """ - - # Fundamental import structure for custom commands depending on which package is available. - gdstk_available = check_import("gdstk") - gdspy_available = check_import("gdspy") - - if gdstk_available: + try: import gdstk - - library = gdstk.Library() - elif gdspy_available: - import gdspy - - library = gdspy.GdsLibrary() - else: + except ImportError as e: raise Tidy3dImportError( - "Python modules 'gdspy' and 'gdstk' not found. To export geometries to .gds " - "files, please install one of those those modules." - ) + "Python module 'gdstk' not found. To export geometries to .gds " + "files, please install it." + ) from e + library = gdstk.Library() cell = library.new_cell(gds_cell_name) self.to_gds(cell, x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) pathlib.Path(fname).parent.mkdir(parents=True, exist_ok=True) library.write_gds(fname) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" raise NotImplementedError(f"Can't compute derivative for 'Geometry': '{type(self)}'.") - def _as_union(self) -> List[Geometry]: + def _as_union(self) -> list[Geometry]: """Return a list of geometries that, united, make up the given geometry.""" if isinstance(self, GeometryGroup): return self.geometries @@ -1680,7 +1547,7 @@ class SimplePlaneIntersection(Geometry, ABC): def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Checks special cases before relying on the complete computation. @@ -1717,13 +1584,13 @@ def transform(p_array): transformed_section = shapely.transform(section, transformation=transform) return transformed_section - else: # Otherwise compute the arbitrary intersection - return self._do_intersections_tilted_plane(normal=normal, origin=origin, to_2D=to_2D) + # Otherwise compute the arbitrary intersection + return self._do_intersections_tilted_plane(normal=normal, origin=origin, to_2D=to_2D) @abstractmethod def _do_intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -1801,7 +1668,9 @@ def finite_length_axis(self) -> float: """ return min(self.length_axis, LARGE_NUMBER) - def intersections_plane(self, x: float = None, y: float = None, z: float = None): + def intersections_plane( + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ): """Returns shapely geometry at plane specified by one non None value of x,y,z. Parameters @@ -1880,7 +1749,7 @@ def _order_axis(self, axis: int) -> int: axis_index.insert(self.axis, 2) return axis_index[axis] - def _order_by_axis(self, plane_val: Any, axis_val: Any, axis: int) -> Tuple[Any, Any]: + def _order_by_axis(self, plane_val: Any, axis_val: Any, axis: int) -> tuple[Any, Any]: """Orders a value in the plane and value along axis in correct (x,y) order for plotting. Note: sometimes if axis=1 and we compute cross section values orthogonal to axis, they can either be x or y in the plots. @@ -1993,8 +1862,7 @@ def _normal_axis(self) -> Axis: """Axis normal to the Box. Errors if box is not planar.""" if self.size.count(0.0) != 1: raise ValidationError( - "Tried to get 'normal_axis' of 'Box' that is not planar. " - f"Given 'size={self.size}.'" + f"Tried to get 'normal_axis' of 'Box' that is not planar. Given 'size={self.size}.'" ) return self.size.index(0.0) @@ -2119,7 +1987,7 @@ def surfaces_with_exclusion(cls, size: Size, center: Coordinate, **kwargs): @verify_packages_import(["trimesh"]) def _do_intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -2164,10 +2032,12 @@ def _do_intersections_tilted_plane( section = mesh.section(plane_origin=origin, plane_normal=normal) if section is None: return [] - path, _ = section.to_planar(to_2D=to_2D) + path, _ = section.to_2D(to_2D=to_2D) return path.polygons_full - def intersections_plane(self, x: float = None, y: float = None, z: float = None): + def intersections_plane( + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ): """Returns shapely geometry at plane specified by one non None value of x,y,z. Parameters @@ -2298,7 +2168,7 @@ def geometry(self): return Box(center=self.center, size=self.size) @cached_property - def zero_dims(self) -> List[Axis]: + def zero_dims(self) -> list[Axis]: """A list of axes along which the :class:`Box` is zero-sized.""" return [dim for dim, size in enumerate(self.size) if size == 0] @@ -2311,7 +2181,7 @@ def _normal_2dmaterial(self) -> Axis: ) return self.size.index(0) - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Box: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> Box: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" new_center = list(self.center) @@ -2322,13 +2192,13 @@ def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Box: def _plot_arrow( self, - direction: Tuple[float, float, float], - x: float = None, - y: float = None, - z: float = None, - color: str = None, - alpha: float = None, - bend_radius: float = None, + direction: tuple[float, float, float], + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + color: Optional[str] = None, + alpha: Optional[float] = None, + bend_radius: Optional[float] = None, bend_axis: Axis = None, both_dirs: bool = False, ax: Ax = None, @@ -2425,7 +2295,9 @@ def _cb(event): event.canvas.mpl_disconnect(arrow.set_shape_cb[0]) transform = arrow.axes.transData.transform - scale = transform((1, 0))[0] - transform((0, 0))[0] + scale_x = transform((1, 0))[0] - transform((0, 0))[0] + scale_y = transform((0, 1))[1] - transform((0, 0))[1] + scale = max(scale_x, scale_y) # <-- Hack: This is a somewhat arbitrary choice. arrow_length = ARROW_LENGTH * event.canvas.figure.get_dpi() / scale if bend_radius: @@ -2496,14 +2368,14 @@ def _surface_area(self, bounds: Bound) -> float: """ Autograd code """ - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" # get gradients w.r.t. each of the 6 faces (in normal direction) - vjps_faces = self.derivative_faces(derivative_info=derivative_info) + vjps_faces = self._derivative_faces(derivative_info=derivative_info) # post-process these values to give the gradients w.r.t. center and size - vjps_center_size = self.derivatives_center_size(vjps_faces=vjps_faces) + vjps_center_size = self._derivatives_center_size(vjps_faces=vjps_faces) # store only the gradients asked for in 'field_paths' derivative_map = {} @@ -2524,7 +2396,7 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM return derivative_map @staticmethod - def derivatives_center_size(vjps_faces: Bound) -> dict[str, Coordinate]: + def _derivatives_center_size(vjps_faces: Bound) -> dict[str, Coordinate]: """Derivatives with respect to the ``center`` and ``size`` fields in the ``Box``.""" vjps_faces_min, vjps_faces_max = np.array(vjps_faces) @@ -2533,12 +2405,12 @@ def derivatives_center_size(vjps_faces: Bound) -> dict[str, Coordinate]: vjp_center = vjps_faces_max - vjps_faces_min vjp_size = (vjps_faces_min + vjps_faces_max) / 2.0 - return dict( - center=tuple(vjp_center.tolist()), - size=tuple(vjp_size.tolist()), - ) + return { + "center": tuple(vjp_center.tolist()), + "size": tuple(vjp_size.tolist()), + } - def derivative_faces(self, derivative_info: DerivativeInfo) -> Bound: + def _derivative_faces(self, derivative_info: DerivativeInfo) -> Bound: """Derivative with respect to normal position of 6 faces of ``Box``.""" # change in permittivity between inside and outside @@ -2546,7 +2418,7 @@ def derivative_faces(self, derivative_info: DerivativeInfo) -> Bound: for min_max_index, _ in enumerate((0, -1)): for axis in range(3): - vjp_face = self.derivative_face( + vjp_face = self._derivative_face( min_max_index=min_max_index, axis_normal=axis, derivative_info=derivative_info, @@ -2557,7 +2429,7 @@ def derivative_faces(self, derivative_info: DerivativeInfo) -> Bound: return vjp_faces - def derivative_face( + def _derivative_face( self, min_max_index: int, axis_normal: Axis, @@ -2748,7 +2620,7 @@ def bounds(self) -> Bound: def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -2945,7 +2817,7 @@ def _normal_2dmaterial(self) -> Axis: return normal - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Transformed: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> Transformed: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" min_bound = np.array([0, 0, 0, 1.0]) @@ -2984,7 +2856,7 @@ class ClipOperation(Geometry): @pydantic.validator("geometry_a", "geometry_b", always=True) def _geometries_untraced(cls, val): """Make sure that ``ClipOperation`` geometries do not contain tracers.""" - traced = val.strip_traced_fields() + traced = val._strip_traced_fields() if traced: raise ValidationError( f"{val.type} contains traced fields {list(traced.keys())}. Note that " @@ -2993,27 +2865,45 @@ def _geometries_untraced(cls, val): return val @staticmethod - def to_polygon_list(base_geometry: Shapely) -> List[Shapely]: + def to_polygon_list(base_geometry: Shapely, cleanup: bool = False) -> list[Shapely]: """Return a list of valid polygons from a shapely geometry, discarding points, lines, and - empty polygons. + empty polygons, and empty triangles within polygons. Parameters ---------- base_geometry : shapely.geometry.base.BaseGeometry Base geometry for inspection. + cleanup: bool = False + If True, removes extremely small features from each polygon's boundary. + This is useful for removing artifacts from 2D plots displayed to the user. Returns ------- List[shapely.geometry.base.BaseGeometry] Valid polygons retrieved from ``base geometry``. """ + unfiltered_geoms = [] if base_geometry.geom_type == "GeometryCollection": - return [p for geom in base_geometry.geoms for p in ClipOperation.to_polygon_list(geom)] + unfiltered_geoms = [ + p for geom in base_geometry.geoms for p in ClipOperation.to_polygon_list(geom) + ] if base_geometry.geom_type == "MultiPolygon": - return [p for p in base_geometry.geoms if not p.is_empty] + unfiltered_geoms = [p for p in base_geometry.geoms if not p.is_empty] if base_geometry.geom_type == "Polygon" and not base_geometry.is_empty: - return [base_geometry] - return [] + unfiltered_geoms = [base_geometry] + geoms = [] + if cleanup: + # Optional: "clean" each of the polygons (by removing extremely small or thin features). + for geom in unfiltered_geoms: + geom_clean = cleanup_shapely_object(geom) + if geom_clean.geom_type == "Polygon": + geoms.append(geom_clean) + if geom_clean.geom_type == "MultiPolygon": + geoms += [p for p in geom_clean.geoms if not p.is_empty] + # Ignore other types of shapely objects (points and lines) + else: + geoms = unfiltered_geoms + return geoms @property def _shapely_operation(self) -> Callable[[Shapely, Shapely], Shapely]: @@ -3039,7 +2929,7 @@ def _bit_operation(self) -> Callable[[Any, Any], Any]: def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -3062,11 +2952,14 @@ def intersections_tilted_plane( b = self.geometry_b.intersections_tilted_plane(normal, origin, to_2D) geom_a = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in a]) geom_b = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in b]) - return ClipOperation.to_polygon_list(self._shapely_operation(geom_a, geom_b)) + return ClipOperation.to_polygon_list( + self._shapely_operation(geom_a, geom_b), + cleanup=True, + ) def intersections_plane( - self, x: float = None, y: float = None, z: float = None - ) -> List[Shapely]: + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ) -> list[Shapely]: """Returns list of shapely geometries at plane specified by one non-None value of x,y,z. Parameters @@ -3089,7 +2982,10 @@ def intersections_plane( b = self.geometry_b.intersections_plane(x, y, z) geom_a = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in a]) geom_b = shapely.unary_union([Geometry.evaluate_inf_shape(g) for g in b]) - return ClipOperation.to_polygon_list(self._shapely_operation(geom_a, geom_b)) + return ClipOperation.to_polygon_list( + self._shapely_operation(geom_a, geom_b), + cleanup=True, + ) @cached_property def bounds(self) -> Bound: @@ -3203,7 +3099,7 @@ def _normal_2dmaterial(self) -> Axis: ) return normal_a - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> ClipOperation: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> ClipOperation: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" new_geom_a = self.geometry_a._update_from_bounds(bounds=bounds, axis=axis) @@ -3214,7 +3110,7 @@ def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> ClipOp class GeometryGroup(Geometry): """A collection of Geometry objects that can be called as a single geometry object.""" - geometries: Tuple[annotate_type(GeometryType), ...] = pydantic.Field( + geometries: tuple[annotate_type(GeometryType), ...] = pydantic.Field( ..., title="Geometries", description="Tuple of geometries in a single grouping. " @@ -3247,7 +3143,7 @@ def bounds(self) -> Bound: def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -3273,8 +3169,8 @@ def intersections_tilted_plane( ] def intersections_plane( - self, x: float = None, y: float = None, z: float = None - ) -> List[Shapely]: + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ) -> list[Shapely]: """Returns list of shapely geometries at plane specified by one non-None value of x,y,z. Parameters @@ -3394,7 +3290,7 @@ def _normal_2dmaterial(self) -> Axis: ) return normal - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> GeometryGroup: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> GeometryGroup: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" new_geometries = [ @@ -3402,26 +3298,124 @@ def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Geomet ] return self.updated_copy(geometries=new_geometries) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" grad_vjps = {} + # create interpolators once for all geometries to avoid redundant field data conversions + interpolators = derivative_info.interpolators or derivative_info.create_interpolators( + dtype=GRADIENT_DTYPE_FLOAT + ) + for field_path in derivative_info.paths: _, index, *geo_path = field_path geo = self.geometries[index] + # pass pre-computed interpolators if available geo_info = derivative_info.updated_copy( - paths=[geo_path], bounds=geo.bounds, eps_approx=True, deep=False + paths=[tuple(geo_path)], + bounds=geo.bounds, + eps_approx=True, + deep=False, + interpolators=interpolators, ) - vjp_dict_geo = geo.compute_derivatives(geo_info) - grad_vjp_values = list(vjp_dict_geo.values()) - if len(grad_vjp_values) != 1: + vjp_dict_geo = geo._compute_derivatives(geo_info) + + if len(vjp_dict_geo) != 1: raise AssertionError("Got multiple gradients for single geometry field.") - grad_vjps[field_path] = grad_vjp_values[0] + grad_vjps[field_path] = vjp_dict_geo.popitem()[1] return grad_vjps +def cleanup_shapely_object(obj: Shapely, tolerance_ratio: float = POLY_TOLERANCE_RATIO) -> Shapely: + """Remove small geometric features from the boundaries of a shapely object including + inward and outward spikes, thin holes, and thin connections between larger regions. + + Parameters + ---------- + obj : shapely + a shapely object (typically a ``Polygon`` or a ``MultiPolygon``) + tolerance_ratio : float = ``POLY_TOLERANCE_RATIO`` + Features on the boundaries of polygons will be discarded if they are smaller + or narrower than ``tolerance_ratio`` multiplied by the size of the object. + + Returns + ------- + Shapely + A new shapely object whose small features (eg. thin spikes or holes) are removed. + + Notes + ----- + This function does not attempt to delete overlapping, nearby, or collinear vertices. + To solve that problem, use ``shapely.simplify()`` afterwards. + """ + if _shapely_is_older_than("2.1"): + log.warning( + "Using old versions of the shapely library (prior to v2.1) may cause " + "plot errors. This can be solved by upgrading to Python 3.10 " + "(or later) and reinstalling Tidy3d.", + log_once=True, + ) + return obj + if obj.is_empty: + return obj + centroid = obj.centroid + object_size = min(obj.bounds[2] - obj.bounds[0], obj.bounds[3] - obj.bounds[1]) + if object_size == 0.0: + return shapely.Polygon([]) + # In order to prevent numerical overflow or underflow errors, we first subtract + # the centroid and divide by (rescale) the size of the object so it is not too big. + normalized_obj = shapely.affinity.affine_transform( + # https://shapely.readthedocs.io/en/stable/manual.html#affine-transformations + obj, + matrix=[ + 1 / object_size, + 0.0, + 0.0, + 1 / object_size, + -centroid.x / object_size, + -centroid.y / object_size, + ], + ) + # Important: Remove any self intersections beforehand using `shapely.make_valid()`. + valid_obj = shapely.make_valid(normalized_obj, method="structure", keep_collapsed=False) + # To get rid of small thin features, erode(shrink), dilate(expand), and erode again. + eroded_obj = shapely.buffer( # This removes outward spikes + valid_obj, + distance=-tolerance_ratio, + cap_style="square", # (optional parameter to reduce computation time) + quad_segs=3, # (optional parameter to reduce computation time) + ) + dilated_obj = shapely.buffer( # This removes inward spikes and tiny holes + eroded_obj, + distance=2 * tolerance_ratio, + cap_style="square", + quad_segs=3, + ) + cleaned_obj = dilated_obj + # Optional: Now shrink the polygon back to the original size. + cleaned_obj = shapely.buffer( + cleaned_obj, + distance=-tolerance_ratio, + cap_style="square", + quad_segs=3, + ) + # Revert to the original scale and position. + rescaled_clean_obj = shapely.affinity.affine_transform( + cleaned_obj, + matrix=[ + object_size, + 0.0, + 0.0, + object_size, + centroid.x, + centroid.y, + ], + ) + return rescaled_clean_obj + + from .utils import GeometryType, from_shapely, vertices_from_shapely # noqa: E402 diff --git a/tidy3d/components/geometry/bound_ops.py b/tidy3d/components/geometry/bound_ops.py new file mode 100644 index 0000000000..2cd3428c2c --- /dev/null +++ b/tidy3d/components/geometry/bound_ops.py @@ -0,0 +1,68 @@ +"""Geometry operations for bounding box type with minimal imports.""" + +from __future__ import annotations + +from math import isclose + +from tidy3d.components.types import Bound +from tidy3d.constants import fp_eps + + +def bounds_intersection(bounds1: Bound, bounds2: Bound) -> Bound: + """Return the bounds that are the intersection of two bounds.""" + rmin1, rmax1 = bounds1 + rmin2, rmax2 = bounds2 + rmin = tuple(max(v1, v2) for v1, v2 in zip(rmin1, rmin2)) + rmax = tuple(min(v1, v2) for v1, v2 in zip(rmax1, rmax2)) + return (rmin, rmax) + + +def bounds_union(bounds1: Bound, bounds2: Bound) -> Bound: + """Return the bounds that are the union of two bounds.""" + rmin1, rmax1 = bounds1 + rmin2, rmax2 = bounds2 + rmin = tuple(min(v1, v2) for v1, v2 in zip(rmin1, rmin2)) + rmax = tuple(max(v1, v2) for v1, v2 in zip(rmax1, rmax2)) + return (rmin, rmax) + + +def bounds_contains( + outer_bounds: Bound, inner_bounds: Bound, rtol: float = fp_eps, atol: float = 0.0 +) -> bool: + """Checks whether ``inner_bounds`` is contained within ``outer_bounds`` within specified tolerances. + + Parameters + ---------- + outer_bounds : Bound + The outer bounds to check containment against + inner_bounds : Bound + The inner bounds to check if contained + rtol : float = fp_eps + Relative tolerance for comparing bounds + atol : float = 0.0 + Absolute tolerance for comparing bounds + + Returns + ------- + bool + True if ``inner_bounds`` is contained within ``outer_bounds`` within tolerances + """ + outer_min, outer_max = outer_bounds + inner_min, inner_max = inner_bounds + for dim in range(3): + outer_min_dim = outer_min[dim] + outer_max_dim = outer_max[dim] + inner_min_dim = inner_min[dim] + inner_max_dim = inner_max[dim] + within_min = ( + isclose(outer_min_dim, inner_min_dim, rel_tol=rtol, abs_tol=atol) + or outer_min_dim <= inner_min_dim + ) + within_max = ( + isclose(outer_max_dim, inner_max_dim, rel_tol=rtol, abs_tol=atol) + or outer_max_dim >= inner_max_dim + ) + + if not within_min or not within_max: + return False + return True diff --git a/tidy3d/components/geometry/mesh.py b/tidy3d/components/geometry/mesh.py index d2e258ee66..391ae01be8 100644 --- a/tidy3d/components/geometry/mesh.py +++ b/tidy3d/components/geometry/mesh.py @@ -3,21 +3,22 @@ from __future__ import annotations from abc import ABC -from typing import List, Optional, Tuple, Union +from typing import Callable, Literal, Optional, Union import numpy as np import pydantic.v1 as pydantic -from ...constants import inf -from ...exceptions import DataError, ValidationError -from ...log import log -from ...packaging import verify_packages_import -from ..base import cached_property -from ..data.data_array import DATA_ARRAY_MAP, TriangleMeshDataArray -from ..data.dataset import TriangleMeshDataset -from ..data.validators import validate_no_nans -from ..types import Ax, Bound, Coordinate, MatrixReal4x4, Shapely -from ..viz import add_ax_if_none, equal_aspect +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import DATA_ARRAY_MAP, TriangleMeshDataArray +from tidy3d.components.data.dataset import TriangleMeshDataset +from tidy3d.components.data.validators import validate_no_nans +from tidy3d.components.types import Ax, Bound, Coordinate, MatrixReal4x4, Shapely +from tidy3d.components.viz import add_ax_if_none, equal_aspect +from tidy3d.constants import fp_eps, inf +from tidy3d.exceptions import DataError, ValidationError +from tidy3d.log import log +from tidy3d.packaging import verify_packages_import + from . import base AREA_SIZE_THRESHOLD = 1e-36 @@ -150,8 +151,8 @@ def from_stl( cls, filename: str, scale: float = 1.0, - origin: Tuple[float, float, float] = (0, 0, 0), - solid_index: int = None, + origin: tuple[float, float, float] = (0, 0, 0), + solid_index: Optional[int] = None, **kwargs, ) -> Union[TriangleMesh, base.GeometryGroup]: """Load a :class:`.TriangleMesh` directly from an STL file. @@ -181,7 +182,7 @@ def from_stl( """ import trimesh - from ..types_extra import TrimeshType + from tidy3d.components.types_extra import TrimeshType def process_single(mesh: TrimeshType) -> TriangleMesh: """Process a single 'trimesh.Trimesh' using scale and origin.""" @@ -253,11 +254,11 @@ def from_triangles(cls, triangles: np.ndarray) -> TriangleMesh: f"Provided 'triangles' must be an N x 3 x 3 array, given {triangles.shape}." ) num_faces = len(triangles) - coords = dict( - face_index=np.arange(num_faces), - vertex_index=np.arange(3), - axis=np.arange(3), - ) + coords = { + "face_index": np.arange(num_faces), + "vertex_index": np.arange(3), + "axis": np.arange(3), + } vertices = TriangleMeshDataArray(triangles, coords=coords) mesh_dataset = TriangleMeshDataset(surface_mesh=vertices) return TriangleMesh(mesh_dataset=mesh_dataset) @@ -308,6 +309,185 @@ def _triangles_to_trimesh( return trimesh.Trimesh(**trimesh.triangles.to_kwargs(triangles)) + @classmethod + def from_height_grid( + cls, + axis: Ax, + direction: Literal["-", "+"], + base: float, + grid: tuple[np.ndarray, np.ndarray], + height: np.ndarray, + ) -> TriangleMesh: + """Construct a TriangleMesh object from grid based height information. + + Parameters + ---------- + axis : Ax + Axis of extrusion. + direction : Literal["-", "+"] + Direction of extrusion. + base : float + Coordinate of the base surface along the geometry's axis. + grid : Tuple[np.ndarray, np.ndarray] + Tuple of two one-dimensional arrays representing the sampling grid (XY, YZ, or ZX + corresponding to values of axis) + height : np.ndarray + Height values sampled on the given grid. Can be 1D (raveled) or 2D (matching grid mesh). + + Returns + ------- + TriangleMesh + The resulting TriangleMesh geometry object. + """ + + x_coords = grid[0] + y_coords = grid[1] + + nx = len(x_coords) + ny = len(y_coords) + nt = nx * ny + + x_mesh, y_mesh = np.meshgrid(x_coords, y_coords, indexing="ij") + + sign = 1 + if direction == "-": + sign = -1 + + flat_height = np.ravel(height) + if flat_height.shape[0] != nt: + raise ValueError( + f"Shape of flattened height array {flat_height.shape} does not match " + f"the number of grid points {nt}." + ) + + if np.any(flat_height < 0): + raise ValueError("All height values must be non-negative.") + + max_h = np.max(flat_height) + min_h_clip = fp_eps * max_h + flat_height = np.clip(flat_height, min_h_clip, inf) + + vertices_raw_list = [ + [np.ravel(x_mesh), np.ravel(y_mesh), base + sign * flat_height], # Alpha surface + [np.ravel(x_mesh), np.ravel(y_mesh), base * np.ones(nt)], + ] + + if direction == "-": + vertices_raw_list = vertices_raw_list[::-1] + + vertices = np.hstack(vertices_raw_list).T + vertices = np.roll(vertices, shift=axis - 2, axis=1) + + q0 = (np.arange(nx - 1)[:, None] * ny + np.arange(ny - 1)[None, :]).ravel() + q1 = (np.arange(1, nx)[:, None] * ny + np.arange(ny - 1)[None, :]).ravel() + q2 = (np.arange(1, nx)[:, None] * ny + np.arange(1, ny)[None, :]).ravel() + q3 = (np.arange(nx - 1)[:, None] * ny + np.arange(1, ny)[None, :]).ravel() + + q0_b = nt + q0 + q1_b = nt + q1 + q2_b = nt + q2 + q3_b = nt + q3 + + top_quads = np.stack((q0, q1, q2, q3), axis=-1) + bottom_quads = np.stack((q0_b, q3_b, q2_b, q1_b), axis=-1) + + s1_q0 = (0 * ny + np.arange(ny - 1)).ravel() + s1_q1 = (0 * ny + np.arange(1, ny)).ravel() + s1_q2 = (nt + 0 * ny + np.arange(1, ny)).ravel() + s1_q3 = (nt + 0 * ny + np.arange(ny - 1)).ravel() + side1_quads = np.stack((s1_q0, s1_q1, s1_q2, s1_q3), axis=-1) + + s2_q0 = ((nx - 1) * ny + np.arange(ny - 1)).ravel() + s2_q1 = (nt + (nx - 1) * ny + np.arange(ny - 1)).ravel() + s2_q2 = (nt + (nx - 1) * ny + np.arange(1, ny)).ravel() + s2_q3 = ((nx - 1) * ny + np.arange(1, ny)).ravel() + side2_quads = np.stack((s2_q0, s2_q1, s2_q2, s2_q3), axis=-1) + + s3_q0 = (np.arange(nx - 1) * ny + 0).ravel() + s3_q1 = (nt + np.arange(nx - 1) * ny + 0).ravel() + s3_q2 = (nt + np.arange(1, nx) * ny + 0).ravel() + s3_q3 = (np.arange(1, nx) * ny + 0).ravel() + side3_quads = np.stack((s3_q0, s3_q1, s3_q2, s3_q3), axis=-1) + + s4_q0 = (np.arange(nx - 1) * ny + ny - 1).ravel() + s4_q1 = (np.arange(1, nx) * ny + ny - 1).ravel() + s4_q2 = (nt + np.arange(1, nx) * ny + ny - 1).ravel() + s4_q3 = (nt + np.arange(nx - 1) * ny + ny - 1).ravel() + side4_quads = np.stack((s4_q0, s4_q1, s4_q2, s4_q3), axis=-1) + + all_quads = np.vstack( + (top_quads, bottom_quads, side1_quads, side2_quads, side3_quads, side4_quads) + ) + + triangles_list = [ + np.stack((all_quads[:, 0], all_quads[:, 1], all_quads[:, 3]), axis=-1), + np.stack((all_quads[:, 3], all_quads[:, 1], all_quads[:, 2]), axis=-1), + ] + tri_faces = np.vstack(triangles_list) + + return cls.from_vertices_faces(vertices=vertices, faces=tri_faces) + + @classmethod + def from_height_function( + cls, + axis: Ax, + direction: Literal["-", "+"], + base: float, + center: tuple[float, float], + size: tuple[float, float], + grid_size: tuple[int, int], + height_func: Callable[[np.ndarray, np.ndarray], np.ndarray], + ) -> TriangleMesh: + """Construct a TriangleMesh object from analytical expression of height function. + The height function should be vectorized to accept 2D meshgrid arrays. + + Parameters + ---------- + axis : Ax + Axis of extrusion. + direction : Literal["-", "+"] + Direction of extrusion. + base : float + Coordinate of the base rectangle along the geometry's axis. + center : Tuple[float, float] + Center of the base rectangle in the plane perpendicular to the extrusion axis + (XY, YZ, or ZX corresponding to values of axis). + size : Tuple[float, float] + Size of the base rectangle in the plane perpendicular to the extrusion axis + (XY, YZ, or ZX corresponding to values of axis). + grid_size : Tuple[int, int] + Number of grid points for discretization of the base rectangle + (XY, YZ, or ZX corresponding to values of axis). + height_func : Callable[[np.ndarray, np.ndarray], np.ndarray] + Vectorized function to compute height values from 2D meshgrid coordinate arrays. + It should take two ndarrays (x_mesh, y_mesh) and return an ndarray of heights. + + Returns + ------- + TriangleMesh + The resulting TriangleMesh geometry object. + """ + x_lin = np.linspace(center[0] - 0.5 * size[0], center[0] + 0.5 * size[0], grid_size[0]) + y_lin = np.linspace(center[1] - 0.5 * size[1], center[1] + 0.5 * size[1], grid_size[1]) + + x_mesh, y_mesh = np.meshgrid(x_lin, y_lin, indexing="ij") + + height_values = height_func(x_mesh, y_mesh) + + if not (isinstance(height_values, np.ndarray) and height_values.shape == x_mesh.shape): + raise ValueError( + f"The 'height_func' must return a NumPy array with shape {x_mesh.shape}, " + f"but got shape {getattr(height_values, 'shape', type(height_values))}." + ) + + return cls.from_height_grid( + axis=axis, + direction=direction, + base=base, + grid=(x_lin, y_lin), + height=height_values, + ) + @cached_property @verify_packages_import(["trimesh"]) def trimesh( @@ -348,7 +528,7 @@ def bounds(self) -> Bound: def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -370,12 +550,12 @@ def intersections_tilted_plane( section = self.trimesh.section(plane_origin=origin, plane_normal=normal) if section is None: return [] - path, _ = section.to_planar(to_2D=to_2D) + path, _ = section.to_2D(to_2D=to_2D) return path.polygons_full def intersections_plane( - self, x: float = None, y: float = None, z: float = None - ) -> List[Shapely]: + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ) -> list[Shapely]: """Returns list of shapely geometries at plane specified by one non-None value of x,y,z. Parameters @@ -423,7 +603,7 @@ def intersections_plane( permutation = self.unpop_axis(identity[2], identity[0:2], axis=axis) mapping[:3, :3] = np.array(permutation).T - section2d, _ = section.to_planar(to_2D=mapping) + section2d, _ = section.to_2D(to_2D=mapping) return list(section2d.polygons_full) except ValueError as e: @@ -475,7 +655,12 @@ def inside( @equal_aspect @add_ax_if_none def plot( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None, **patch_kwargs + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + **patch_kwargs, ) -> Ax: """Plot geometry cross section at single (x,y,z) coordinate. diff --git a/tidy3d/components/geometry/polyslab.py b/tidy3d/components/geometry/polyslab.py index 51b66ab8a1..41a7a2ebf3 100644 --- a/tidy3d/components/geometry/polyslab.py +++ b/tidy3d/components/geometry/polyslab.py @@ -4,23 +4,27 @@ import math from copy import copy -from typing import List, Tuple, Union +from functools import lru_cache +from typing import Optional, Union import autograd.numpy as np import pydantic.v1 as pydantic import shapely from autograd.tracer import getval, isbox - -from ...constants import LARGE_NUMBER, MICROMETER, fp_eps -from ...exceptions import SetupError, ValidationError -from ...log import log -from ...packaging import verify_packages_import -from ..autograd import AutogradFieldMap, TracedVertices, get_static -from ..autograd.derivative_utils import DerivativeInfo, DerivativeSurfaceMesh -from ..autograd.types import TracedFloat -from ..base import cached_property, skip_if_fields_missing -from ..transformation import ReflectionFromPlane, RotationAroundAxis -from ..types import ( +from numpy.polynomial.legendre import leggauss as _leggauss + +from tidy3d.components.autograd import AutogradFieldMap, TracedVertices, get_static +from tidy3d.components.autograd.constants import ( + EDGE_CLIP_TOLERANCE, + GAUSS_QUADRATURE_ORDER, + GRADIENT_DTYPE_FLOAT, + QUAD_SAMPLE_FRACTION, +) +from tidy3d.components.autograd.derivative_utils import DerivativeInfo +from tidy3d.components.autograd.types import TracedFloat +from tidy3d.components.base import cached_property, skip_if_fields_missing +from tidy3d.components.transformation import ReflectionFromPlane, RotationAroundAxis +from tidy3d.components.types import ( ArrayFloat1D, ArrayFloat2D, ArrayLike, @@ -31,6 +35,11 @@ PlanePosition, Shapely, ) +from tidy3d.constants import LARGE_NUMBER, MICROMETER, fp_eps +from tidy3d.exceptions import SetupError, Tidy3dImportError, ValidationError +from tidy3d.log import log +from tidy3d.packaging import verify_packages_import + from . import base, triangulation # sampling polygon along dilation for validating polygon to be @@ -47,8 +56,12 @@ _MIN_POLYGON_AREA = fp_eps -# number of points per dimension when discretizing polyslab faces for slab bounds gradients -_NUM_PTS_DIM_SLAB_BOUNDS = 30 + +@lru_cache(maxsize=128) +def leggauss(n): + """Cached version of leggauss with dtype conversions.""" + g, w = _leggauss(n) + return g.astype(GRADIENT_DTYPE_FLOAT, copy=False), w.astype(GRADIENT_DTYPE_FLOAT, copy=False) class PolySlab(base.Planar): @@ -60,7 +73,7 @@ class PolySlab(base.Planar): >>> p = PolySlab(vertices=vertices, axis=2, slab_bounds=(-1, 1)) """ - slab_bounds: Tuple[TracedFloat, TracedFloat] = pydantic.Field( + slab_bounds: tuple[TracedFloat, TracedFloat] = pydantic.Field( ..., title="Slab Bounds", description="Minimum and maximum positions of the slab along axis dimension.", @@ -208,7 +221,7 @@ def no_self_intersecting_polygon_during_extrusion(cls, val, values): slab_min, slab_max = values["slab_bounds"] slab_bounds = [getval(slab_min), getval(slab_max)] - # Fist, check vertex-vertex crossing at any point during extrusion + # first, check vertex-vertex crossing at any point during extrusion length = slab_bounds[1] - slab_bounds[0] dist = [-length * np.tan(values["sidewall_angle"])] # reverse the dilation value if it's defined on the top @@ -252,20 +265,20 @@ def from_gds( cls, gds_cell, axis: Axis, - slab_bounds: Tuple[float, float], + slab_bounds: tuple[float, float], gds_layer: int, - gds_dtype: int = None, + gds_dtype: Optional[int] = None, gds_scale: pydantic.PositiveFloat = 1.0, dilation: float = 0.0, sidewall_angle: float = 0, reference_plane: PlanePosition = "middle", - ) -> List[PolySlab]: - """Import :class:`PolySlab` from a ``gdstk.Cell`` or a ``gdspy.Cell``. + ) -> list[PolySlab]: + """Import :class:`PolySlab` from a ``gdstk.Cell``. Parameters ---------- - gds_cell : Union[gdstk.Cell, gdspy.Cell] - ``gdstk.Cell`` or ``gdspy.Cell`` containing 2D geometric data. + gds_cell : gdstk.Cell + ``gdstk.Cell`` containing 2D geometric data. axis : int Integer index into the polygon's slab axis. (0,1,2) -> (x,y,z). slab_bounds: Tuple[float, float] @@ -316,15 +329,15 @@ def from_gds( def _load_gds_vertices( gds_cell, gds_layer: int, - gds_dtype: int = None, + gds_dtype: Optional[int] = None, gds_scale: pydantic.PositiveFloat = 1.0, - ) -> List[ArrayFloat2D]: - """Import :class:`PolySlab` from a ``gdstk.Cell`` or a ``gdspy.Cell``. + ) -> list[ArrayFloat2D]: + """Import :class:`PolySlab` from a ``gdstk.Cell``. Parameters ---------- - gds_cell : Union[gdstk.Cell, gdspy.Cell] - ``gdstk.Cell`` or ``gdspy.Cell`` containing 2D geometric data. + gds_cell : gdstk.Cell + ``gdstk.Cell`` containing 2D geometric data. gds_layer : int Layer index in the ``gds_cell``. gds_dtype : int = None @@ -340,26 +353,27 @@ def _load_gds_vertices( List[ArrayFloat2D] List of :class:`.ArrayFloat2D` """ + import gdstk - # switch the GDS cell loader function based on the class name string - # TODO: make this more robust in future releases gds_cell_class_name = str(gds_cell.__class__) - - if "gdstk" in gds_cell_class_name: - gds_loader_fn = base.Geometry.load_gds_vertices_gdstk - - elif "gdspy" in gds_cell_class_name: - gds_loader_fn = base.Geometry.load_gds_vertices_gdspy - - else: + if not isinstance(gds_cell, gdstk.Cell): + if ( + "gdstk" in gds_cell_class_name + ): # Check if it might be a gdstk cell but gdstk is not found + raise Tidy3dImportError( + "Module 'gdstk' not found. It is required to import gdstk cells." + ) raise ValueError( f"validate 'gds_cell' of type '{gds_cell_class_name}' " - "does not seem to be associated with 'gdstk' or 'gdspy' packages " + "does not seem to be associated with 'gdstk' package " "and therefore can't be loaded by Tidy3D." ) - all_vertices = gds_loader_fn( - gds_cell=gds_cell, gds_layer=gds_layer, gds_dtype=gds_dtype, gds_scale=gds_scale + all_vertices = base.Geometry.load_gds_vertices_gdstk( + gds_cell=gds_cell, + gds_layer=gds_layer, + gds_dtype=gds_dtype, + gds_scale=gds_scale, ) # convert vertices into polyslabs @@ -466,7 +480,7 @@ def _normal_2dmaterial(self) -> Axis: raise ValidationError("'Medium2D' requires the 'PolySlab' bounds to be equal.") return self.axis - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> PolySlab: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> PolySlab: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" if axis != self.axis: @@ -523,14 +537,6 @@ def inside( z_local = z - z0 # distance to the middle dist = -z_local * self._tanq - # # Leaving this function and commented out lines using it below in case we want to revert - # # to it at some point, e.g. if we introduce a MATPLOTLIB_INSTALLED flag. - # def contains_pointwise(face_polygon): - # def fun_contain(xy_point): - # point = shapely.Point(xy_point) - # return face_polygon.covers(point) - # return fun_contain - if isinstance(x, np.ndarray): inside_polygon = np.zeros_like(inside_height) xs_slab = x[inside_height] @@ -578,7 +584,7 @@ def _move_axis_reverse(arr): @verify_packages_import(["trimesh"]) def _do_intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -601,7 +607,8 @@ def _do_intersections_tilted_plane( if len(self.base_polygon) > _MAX_POLYSLAB_VERTICES_FOR_TRIANGULATION: log.warning( - "Processing of PolySlabs with large numbers of vertices can be slow.", log_once=True + f"Processing PolySlabs with over {_MAX_POLYSLAB_VERTICES_FOR_TRIANGULATION} vertices can be slow.", + log_once=True, ) base_triangles = triangulation.triangulate(self.base_polygon) top_triangles = ( @@ -627,7 +634,7 @@ def _do_intersections_tilted_plane( section = mesh.section(plane_origin=origin, plane_normal=normal) if section is None: return [] - path, _ = section.to_planar(to_2D=to_2D) + path, _ = section.to_2D(to_2D=to_2D) return path.polygons_full def _intersections_normal(self, z: float): @@ -799,8 +806,12 @@ def _find_intersecting_height(self, position: float, axis: int) -> np.ndarray: return height def _find_intersecting_ys_angle_vertical( - self, vertices: np.ndarray, position: float, axis: int, exclude_on_vertices: bool = False - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + self, + vertices: np.ndarray, + position: float, + axis: int, + exclude_on_vertices: bool = False, + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """Finds pairs of forward and backwards vertices where polygon intersects position at axis, Find intersection point (in y) assuming straight line,and intersecting angle between plane and edges. (For unslanted polyslab). @@ -880,7 +891,7 @@ def _find_intersecting_ys_angle_vertical( def _find_intersecting_ys_angle_slant( self, vertices: np.ndarray, position: float, axis: int - ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + ) -> tuple[np.ndarray, np.ndarray, np.ndarray]: """Finds pairs of forward and backwards vertices where polygon intersects position at axis, Find intersection point (in y) assuming straight line,and intersecting angle between plane and edges. (For slanted polyslab) @@ -1148,7 +1159,10 @@ def _edge_events_detection( return True # sample at a few dilation values - dist_list = dilation * np.linspace(0, 1, 1 + _N_SAMPLE_POLYGON_INTERSECT)[1:] + dist_list = ( + dilation + * np.linspace(0, 1, 1 + _N_SAMPLE_POLYGON_INTERSECT, dtype=GRADIENT_DTYPE_FLOAT)[1:] + ) for dist in dist_list: # offset: we offset the vertices first, and then use shapely to make it proper # in principle, one can offset with shapely.buffer directly, but shapely somehow @@ -1252,7 +1266,7 @@ def normalize(v): @staticmethod def _shift_vertices( vertices: np.ndarray, dist - ) -> Tuple[np.ndarray, np.ndarray, Tuple[np.ndarray, np.ndarray]]: + ) -> tuple[np.ndarray, np.ndarray, tuple[np.ndarray, np.ndarray]]: """Shifts the vertices of a polygon outward uniformly by distances `dists`. @@ -1310,10 +1324,16 @@ def normalize(v): shift_x = shift_total[0, :] shift_y = shift_total[1, :] - return np.swapaxes(vs_orig + shift_total, -2, -1), parallel_shift, (shift_x, shift_y) + return ( + np.swapaxes(vs_orig + shift_total, -2, -1), + parallel_shift, + (shift_x, shift_y), + ) @staticmethod - def _edge_length_and_reduction_rate(vertices: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: + def _edge_length_and_reduction_rate( + vertices: np.ndarray, + ) -> tuple[np.ndarray, np.ndarray]: """Edge length of reduction rate of each edge with unit offset length. Parameters @@ -1354,7 +1374,7 @@ def _heal_polygon(vertices: np.ndarray) -> np.ndarray: shapely_poly = PolySlab.make_shapely_polygon(vertices) if shapely_poly.is_valid: return vertices - elif isbox(vertices): + if isbox(vertices): raise NotImplementedError( "The dilation caused damage to the polygon. " "Automatically healing this is currently not supported when " @@ -1415,220 +1435,580 @@ def _surface_area(self, bounds: Bound) -> float: """ Autograd code """ - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: - """Compute the adjoint derivatives for this object.""" + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + """ + Return VJPs while handling several edge-cases: - vjps = {} + - If the slab volume does not overlap the simulation, all grads are zero + (one warning is issued). + - Faces that lie completely outside the simulation give zero ``slab_bounds`` + gradients; this includes the +/- inf cases. + - A 2d simulation collapses the surface integral to a line integral + """ + vjps: AutogradFieldMap = {} + + sim_min, sim_max = map(np.asarray, derivative_info.bounds_intersect) + extents = sim_max - sim_min + is_2d = np.isclose(extents[self.axis], 0.0) - for key in derivative_info.paths: - if key == ("vertices",): - vjp = self.compute_derivative_vertices(derivative_info=derivative_info) - vjps[key] = vjp + # early return if polyslab is not in simulation domain + slab_min, slab_max = self.slab_bounds + if (slab_max <= sim_min[self.axis]) or (slab_min >= sim_max[self.axis]): + log.warning( + "'PolySlab' lies completely outside the simulation domain.", + log_once=True, + ) + for p in derivative_info.paths: + vjps[p] = np.zeros_like(self.vertices) if p == ("vertices",) else 0.0 + return vjps + + # create interpolators once for ALL derivative computations + # use provided interpolators if available to avoid redundant field data conversions + interpolators = derivative_info.interpolators or derivative_info.create_interpolators( + dtype=GRADIENT_DTYPE_FLOAT + ) - elif key[0] == "slab_bounds": - min_max_index = key[1] - vjp_face = self.compute_derivative_slab_face( - derivative_info=derivative_info, min_max_index=min_max_index + for path in derivative_info.paths: + if path == ("vertices",): + vjps[path] = self._compute_derivative_vertices( + derivative_info, sim_min, sim_max, is_2d, interpolators ) + elif path[0] == "slab_bounds": + idx = path[1] + face_coord = self.slab_bounds[idx] + + # face entirely outside -> gradient 0 + if ( + np.isinf(face_coord) + or face_coord < sim_min[self.axis] + or face_coord > sim_max[self.axis] + or is_2d + ): + vjps[path] = 0.0 + continue + + v = self._compute_derivative_slab_bounds(derivative_info, idx, interpolators) + # outward-normal convention + if idx == 0: + v *= -1 + vjps[path] = v + else: + raise ValueError(f"No derivative defined w.r.t. 'PolySlab' field '{path}'.") - # for ``slab_bounds[0]``, the ``VJP_face`` gives VJP for shifting face out. - # corresponds to a decrease ``slab_bounds[0]``. So we need -1 sign. - if min_max_index == 0: - vjp_face *= -1 + return vjps - vjps[key] = vjp_face + def _compute_derivative_slab_bounds( + self, derivative_info: DerivativeInfo, min_max_index: int, interpolators: dict + ) -> float: + """VJP for one of the two horizontal faces of a ``PolySlab``. - else: - raise ValueError(f"No derivative defined with respect to 'PolySlab' field '{key}'.") + The face is discretized into a Cartesian grid of small planar patches + whose linear size does not exceed ``_VJP_SAMPLE_SPACING``. The adjoint surface + integral is evaluated on every retained patch; the resulting derivative + is split equally between the two vertices that bound the edge segment. + """ + # rmin/rmax over the geometry and simulation box + rmin, rmax = derivative_info.bounds_intersect + _, (r1_min, r2_min) = self.pop_axis(rmin, axis=self.axis) + _, (r1_max, r2_max) = self.pop_axis(rmax, axis=self.axis) + ax_val = self.slab_bounds[min_max_index] + + # planar grid resolution, clipped to polygon bounding box + face_verts = self.base_polygon if min_max_index == 0 else self.top_polygon + face_poly = shapely.Polygon(face_verts).buffer(fp_eps) + + # limit the patch grid to the face that lives inside the simulation box + poly_min_r1, poly_min_r2, poly_max_r1, poly_max_r2 = face_poly.bounds + r1_min = max(r1_min, poly_min_r1) + r1_max = min(r1_max, poly_max_r1) + r2_min = max(r2_min, poly_min_r2) + r2_max = min(r2_max, poly_max_r2) + + if (r1_max <= r1_min) and (r2_max <= r2_min): + # the polygon does not intersect the current simulation slice + return 0.0 - return vjps + # re-compute the extents after clipping to the polygon bounds + extents = np.array([r1_max - r1_min, r2_max - r2_min]) - def compute_derivative_slab_face( - self, derivative_info: DerivativeInfo, min_max_index: int - ) -> TracedVertices: - """Derivative with respect to slab_bounds.""" + # choose surface or line integral + integral_fun = ( + self.compute_derivative_slab_bounds_line + if np.isclose(extents, 0).any() + else self.compute_derivative_slab_bounds_surface + ) + return integral_fun( + derivative_info, + extents, + r1_min, + r1_max, + r2_min, + r2_max, + ax_val, + face_poly, + min_max_index, + interpolators, + ) - rmin, rmax = derivative_info.bounds - ax_min, (r1_min, r2_min) = self.pop_axis(rmin, axis=self.axis) - ax_max, (r1_max, r2_max) = self.pop_axis(rmax, axis=self.axis) + def compute_derivative_slab_bounds_line( + self, + derivative_info: DerivativeInfo, + extents: np.ndarray, + r1_min: float, + r1_max: float, + r2_min: float, + r2_max: float, + ax_val: float, + face_poly: shapely.Polygon, + min_max_index: int, + interpolators: dict, + ) -> float: + """Handle degenerate line cross-section case""" + line_dim = 1 if np.isclose(extents[0], 0) else 0 + + poly_min_r1, poly_min_r2, poly_max_r1, poly_max_r2 = face_poly.bounds + if line_dim == 0: # x varies, y is fixed + l_min = max(r1_min, poly_min_r1) + l_max = min(r1_max, poly_max_r1) + else: # y varies, x is fixed + l_min = max(r2_min, poly_min_r2) + l_max = min(r2_max, poly_max_r2) + + length = l_max - l_min + if np.isclose(length, 0): + return 0.0 - num_1 = 1 if r1_min == r1_max else _NUM_PTS_DIM_SLAB_BOUNDS - num_2 = 1 if r2_min == r2_max else _NUM_PTS_DIM_SLAB_BOUNDS + dx = derivative_info.adaptive_vjp_spacing() + n_seg = max(1, int(np.ceil(length / dx))) + coords = np.linspace(l_min, l_max, 2 * n_seg + 1, dtype=GRADIENT_DTYPE_FLOAT)[1::2] - num_cells = num_1 * num_2 - ones = np.ones(num_cells) - zeros = np.zeros(num_cells) + # build XY coordinates and in-plane direction vectors + if line_dim == 0: + xy = np.column_stack((coords, np.full_like(coords, r2_min))) + dir_vec_plane = np.column_stack((np.ones_like(coords), np.zeros_like(coords))) + else: + xy = np.column_stack((np.full_like(coords, r1_min), coords)) + dir_vec_plane = np.column_stack((np.zeros_like(coords), np.ones_like(coords))) - def meshgrid_flatten_stack(*args) -> np.ndarray: - """Take set of `d` coords, meshgrid them, flatten, and assemble in `(N, d)` array.""" - coords = np.meshgrid(*args, indexing="ij") - coords = [c.flatten() for c in coords] - return np.stack(coords, axis=-1) + inside = shapely.contains_xy(face_poly, xy[:, 0], xy[:, 1]) + if not inside.any(): + return 0.0 - # get center points and areas - r1_centers = np.linspace(r1_min, r1_max, 2 * num_1 + 1)[1::2] - r2_centers = np.linspace(r2_min, r2_max, 2 * num_2 + 1)[1::2] - planar_centers = meshgrid_flatten_stack(r1_centers, r2_centers) + xy = xy[inside] + dir_vec_plane = dir_vec_plane[inside] + n_pts = len(xy) - area = 1.0 - for rmin, rmax in zip((r1_min, r2_min), (r1_max, r2_max)): - if rmin != rmax: - area *= rmax - rmin + centers_xyz = self.unpop_axis_vect(np.full(n_pts, ax_val), xy) + areas = np.full(n_pts, length / n_seg) # patch length - areas = area * np.ones(num_cells) / num_cells + normals_xyz = self.unpop_axis_vect( + np.full(n_pts, -1 if min_max_index == 0 else 1), + np.zeros_like(xy), + ) + perps1_xyz = self.unpop_axis_vect(np.zeros(n_pts), dir_vec_plane) + perps2_xyz = self.unpop_axis_vect(np.zeros(n_pts), np.zeros_like(dir_vec_plane)) - def get_grad(min_max_index: int) -> float: - """Compute gradient for either min or max dimension.""" + vjps = derivative_info.evaluate_gradient_at_points( + centers_xyz, normals_xyz, perps1_xyz, perps2_xyz, interpolators + ) + return np.real(np.sum(vjps * areas)).item() - # select the normal sign and the axis value - if min_max_index == 0: - ax_val = ax_min - else: - ax_val = ax_max + def compute_derivative_slab_bounds_surface( + self, + derivative_info: DerivativeInfo, + extents: np.ndarray, + r1_min: float, + r1_max: float, + r2_min: float, + r2_max: float, + ax_val: float, + face_poly: shapely.Polygon, + min_max_index: int, + interpolators: dict, + ) -> float: + """2d surface integral on a Gauss quadrature grid""" + dx = derivative_info.adaptive_vjp_spacing() - edge_centers_xyz = self.unpop_axis_vect(ones * ax_val, planar_centers) + # uniform grid would use n1 x n2 points + n1_uniform, n2_uniform = np.maximum(1, np.ceil(extents / dx).astype(int)) - # construct basis functions - normals = self.unpop_axis_vect(ones, np.stack((zeros, zeros), axis=-1)) - perps1 = self.unpop_axis_vect(zeros, np.stack((ones, zeros), axis=-1)) - perps2 = self.unpop_axis_vect(zeros, np.stack((zeros, ones), axis=-1)) + # use ~1/2 Gauss points in each direction for similar accuracy + n1 = max(2, n1_uniform // 2) + n2 = max(2, n2_uniform // 2) - rr1, rr2, axx_val = meshgrid_flatten_stack(r1_centers, r2_centers, ax_val).T + g1, w1 = leggauss(n1) + g2, w2 = leggauss(n2) - xx, yy, zz = self.unpop_axis_vect(axx_val, np.stack((rr1, rr2), axis=-1)).T + coords1 = (0.5 * (r1_max - r1_min) * g1 + 0.5 * (r1_max + r1_min)).astype( + GRADIENT_DTYPE_FLOAT, copy=False + ) + coords2 = (0.5 * (r2_max - r2_min) * g2 + 0.5 * (r2_max + r2_min)).astype( + GRADIENT_DTYPE_FLOAT, copy=False + ) - inside = self.inside(xx, yy, zz).squeeze().flatten() + r1_grid, r2_grid = np.meshgrid(coords1, coords2, indexing="ij") + r1_flat = r1_grid.flatten() + r2_flat = r2_grid.flatten() + pts = np.column_stack((r1_flat, r2_flat)) - areas_masked = areas * inside + in_face = shapely.contains_xy(face_poly, pts[:, 0], pts[:, 1]) + if not in_face.any(): + return 0.0 - # compute DerivativeSurfaceMesh for each top and bottom. - surface_mesh = DerivativeSurfaceMesh( - centers=edge_centers_xyz, - areas=areas_masked, - normals=normals, - perps1=perps1, - perps2=perps2, - ) + xyz = self.unpop_axis_vect( + np.full(in_face.sum(), ax_val, dtype=GRADIENT_DTYPE_FLOAT), pts[in_face] + ) + n_patches = xyz.shape[0] - grads = derivative_info.grad_surfaces(surface_mesh=surface_mesh) - vjp = np.real(np.sum(grads).item()) + normals_xyz = self.unpop_axis_vect( + np.full(n_patches, -1 if min_max_index == 0 else 1, dtype=GRADIENT_DTYPE_FLOAT), + np.zeros((n_patches, 2), dtype=GRADIENT_DTYPE_FLOAT), + ) + perps1_xyz = self.unpop_axis_vect( + np.zeros(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + np.column_stack( + ( + np.ones(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + np.zeros(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + ) + ), + ) + perps2_xyz = self.unpop_axis_vect( + np.zeros(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + np.column_stack( + ( + np.zeros(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + np.ones(n_patches, dtype=GRADIENT_DTYPE_FLOAT), + ) + ), + ) - return vjp + w1_grid, w2_grid = np.meshgrid(w1, w2, indexing="ij") + weights_flat = (w1_grid * w2_grid).flatten()[in_face] + jacobian = 0.25 * (r1_max - r1_min) * (r2_max - r2_min) - return get_grad(min_max_index) + # area-based correction for non-rectangular domains (e.g. concave polygon) + # for constant integrand, integral should equal polygon area + sum_weights = np.sum(weights_flat) + if sum_weights > 0: + area_correction = face_poly.area / (sum_weights * jacobian) + weights_flat = weights_flat * area_correction - def compute_derivative_slab_face_single_pt( - self, derivative_info: DerivativeInfo, min_max_index: int - ) -> TracedVertices: - """Derivative with respect to slab faces (single point approximation).""" + vjps = derivative_info.evaluate_gradient_at_points( + xyz, normals_xyz, perps1_xyz, perps2_xyz, interpolators + ) + return np.real(np.sum(vjps * weights_flat * jacobian)).item() - self_static = self.to_static() + def _compute_derivative_vertices( + self, + derivative_info: DerivativeInfo, + sim_min: np.ndarray, + sim_max: np.ndarray, + is_2d: bool = False, + interpolators: Optional[dict] = None, + ) -> np.ndarray: + """VJP for the vertices of a ``PolySlab``. + + Each side-wall is sliced in the **in-plane** direction (along the edge) + and, when applicable, in the **out-of-plane** direction (along the + extrusion axis) so that every rectangular surface patch is no larger + than ``_VJP_SAMPLE_SPACING`` in any dimension. The adjoint surface + integral is evaluated on every retained patch; the resulting force is + split (weighted) between the two vertices that bound the edge segment. + + Special cases: + - Pure 2d simulations - integral collapses to a line; only one z-slice is taken. + - Partial overlap with the simulation box - patches falling + outside ``[sim_min, sim_max]`` are skipped. + - Degenerate edges (zero length) - ignored. + """ + vertices = np.asarray(self.vertices, dtype=GRADIENT_DTYPE_FLOAT) + next_v = np.roll(vertices, -1, axis=0) + edges = next_v - vertices + basis = self.edge_basis_vectors(edges) + dx = derivative_info.adaptive_vjp_spacing() + + # compute z‐slices + z0 = max(self.slab_bounds[0], sim_min[self.axis]) + z1 = min(self.slab_bounds[1], sim_max[self.axis]) + + # early return if no z-slices + if (not is_2d) and z1 <= z0: + return np.zeros_like(vertices) + + if is_2d: + z_centers = np.array([self.center_axis], dtype=GRADIENT_DTYPE_FLOAT) + dz_surf = 1.0 + else: + n_z = max(1, int(np.ceil((z1 - z0) / dx))) + dz = (z1 - z0) / n_z + dz_surf = dz / np.cos(self.sidewall_angle) + z_centers = np.linspace(z0 + dz / 2, z1 - dz / 2, n_z, dtype=GRADIENT_DTYPE_FLOAT) - center_r1, center_r2 = np.mean(self_static.vertices, axis=0) - center_axis = self_static.slab_bounds[min_max_index] - center_xyz = self.unpop_axis(center_axis, (center_r1, center_r2), axis=self.axis) + vjp_per_vertex = np.zeros_like(vertices, dtype=float) + normals_2d = np.delete(basis["norm"], self.axis, axis=1) - area = self_static._area(self_static.vertices) + # use provided interpolators or create them if not provided + if interpolators is None: + interpolators = derivative_info.create_interpolators(dtype=GRADIENT_DTYPE_FLOAT) - norm = self.unpop_axis(1, (0, 0), axis=self.axis) - perp1 = self.unpop_axis(0, (0, 1), axis=self.axis) - perp2 = self.unpop_axis(0, (1, 0), axis=self.axis) + def compute_edge_clip_bounds(v0_3d, v1_3d, sim_min, sim_max): + """ + Compute parametric bounds [t_start, t_end] for the portion of edge + (v0_3d -> v1_3d) that lies within [sim_min, sim_max]. - surface_mesh = DerivativeSurfaceMesh( - centers=[center_xyz], - areas=[area], - normals=[norm], - perps1=[perp1], - perps2=[perp2], - ) + Returns: + - (t_start, t_end): parametric bounds, or None if edge is fully outside + """ + t_start, t_end = 0.0, 1.0 + + for dim in range(3): + v0_d, v1_d = v0_3d[dim], v1_3d[dim] + min_d, max_d = sim_min[dim], sim_max[dim] + + if np.isclose(v0_d, v1_d): + if v0_d < min_d or v0_d > max_d: + return None + continue + + t_min = (min_d - v0_d) / (v1_d - v0_d) + t_max = (max_d - v0_d) / (v1_d - v0_d) + + if t_min > t_max: + t_min, t_max = t_max, t_min + + t_start = max(t_start, t_min) + t_end = min(t_end, t_max) + + if t_start >= t_end: + return None + + # avoid numerical issues at boundaries + if t_end <= t_start + EDGE_CLIP_TOLERANCE: + return None + + return (t_start, t_end) + + # estimate total number of patches for pre-allocation + # this avoids repeated list.extend calls + estimated_patches = 0 + n_edges = len(vertices) + for ei in range(n_edges): + v0, v1 = vertices[ei], next_v[ei] + L = np.linalg.norm(v1 - v0) + if not np.isclose(L, 0.0): + # estimate samples per edge (conservative estimate) + n_samples = max(1, int(np.ceil(L / dx) * 0.4)) # 40% of uniform for Gauss + estimated_patches += n_samples * len(z_centers) + + # pre-allocate arrays with estimated size + # over-allocate by 20% to handle edge cases, will trim later + estimated_patches = int(estimated_patches * 1.2) + all_centers = np.empty((estimated_patches, 3), dtype=GRADIENT_DTYPE_FLOAT) + all_areas = np.empty(estimated_patches, dtype=GRADIENT_DTYPE_FLOAT) + all_normals = np.empty((estimated_patches, 3), dtype=GRADIENT_DTYPE_FLOAT) + all_perps1 = np.empty((estimated_patches, 3), dtype=GRADIENT_DTYPE_FLOAT) + all_perps2 = np.empty((estimated_patches, 3), dtype=GRADIENT_DTYPE_FLOAT) + all_edge_info = [] # keep as list since it stores tuples + + # track actual number of patches + patch_idx = 0 + + def get_adaptive_samples(L, dx, t_start=0.0, t_end=1.0): + """Get sampling points and weights along edge using optimal quadrature. + + Parameters: + - L: Full edge length + - dx: Target spacing + - t_start, t_end: Parametric bounds for clipped edges (0 <= t_start < t_end <= 1) + + Returns: + - s: Parametric coordinates in [t_start, t_end] + - weights: Quadrature weights (sum to t_end - t_start) + """ + # compute effective length for the clipped portion + L_effective = L * (t_end - t_start) + n_uniform = max(1, int(np.ceil(L_effective / dx))) - grads = derivative_info.grad_surfaces(surface_mesh=surface_mesh) - vjp = np.real(np.sum(grads).item()) + # Gauss quadrature is more accurate than uniform sampling + if n_uniform <= 3: + n_gauss = n_uniform # for very short edges, keep same number + else: + n_gauss = max( + 2, int(n_uniform * QUAD_SAMPLE_FRACTION) + ) # use 40% of points for longer edges - return vjp + if n_gauss <= GAUSS_QUADRATURE_ORDER: + g, w = leggauss(n_gauss) - def compute_derivative_vertices(self, derivative_info: DerivativeInfo) -> TracedVertices: - # derivative w.r.t each edge + # map from [-1, 1] to [t_start, t_end] + s = (0.5 * (t_end - t_start) * g + 0.5 * (t_end + t_start)).astype( + GRADIENT_DTYPE_FLOAT, copy=False + ) + weights = (w * 0.5 * (t_end - t_start)).astype(GRADIENT_DTYPE_FLOAT, copy=False) + else: + # for longer edges, use composite Gauss quadrature + pts_per_interval = GAUSS_QUADRATURE_ORDER + n_intervals = max(1, (n_gauss + pts_per_interval - 1) // pts_per_interval) - vertices = np.array(self.vertices) - num_vertices, _ = vertices.shape + g_ref, w_ref = leggauss(pts_per_interval) - # compute edges between vertices + s_list = [] + w_list = [] - vertices_next = np.roll(self.vertices, axis=0, shift=-1) - edges = vertices_next - vertices + for i in range(n_intervals): + # sub-interval bounds in [0, 1] + a = i / n_intervals + b = (i + 1) / n_intervals - # compute center positions between each edge - edge_centers_plane = (vertices_next + vertices) / 2.0 - edge_centers_axis = self.center_axis * np.ones(num_vertices) - edge_centers_xyz = self.unpop_axis_vect(edge_centers_axis, edge_centers_plane) + # map to [t_start, t_end] + a_mapped = t_start + a * (t_end - t_start) + b_mapped = t_start + b * (t_end - t_start) - if edge_centers_xyz.shape != (num_vertices, 3): - raise AssertionError("something bad happened") + # transform Gauss points to sub-interval [a_mapped, b_mapped] + s_interval = 0.5 * (b_mapped - a_mapped) * g_ref + 0.5 * (b_mapped + a_mapped) + w_interval = 0.5 * (b_mapped - a_mapped) * w_ref - # get basis vectors for every edge segment - basis_vectors = self.edge_basis_vectors(edges=edges) + s_list.extend(s_interval) + w_list.extend(w_interval) - # scale by edge area - edge_lengths = np.linalg.norm(edges, axis=-1) - edge_areas = edge_lengths + s = np.array(s_list, dtype=GRADIENT_DTYPE_FLOAT) + weights = np.array(w_list, dtype=GRADIENT_DTYPE_FLOAT) - # correction to edge area based on sidewall distance along slab axis - slab_height = abs(float(np.squeeze(np.diff(self.slab_bounds)))) - if not np.isinf(slab_height): - edge_areas *= slab_height + return s, weights - surface_mesh = DerivativeSurfaceMesh( - centers=edge_centers_xyz, - areas=edge_areas, - normals=basis_vectors["norm"], - perps1=basis_vectors["perp1"], - perps2=basis_vectors["perp2"], - ) + # pre-compute 2D bounding box for edge clipping optimization + sim_min_2d = np.delete(sim_min, self.axis) + sim_max_2d = np.delete(sim_max, self.axis) - vjps_edges = derivative_info.grad_surfaces(surface_mesh=surface_mesh) + for ei, (v0, v1) in enumerate(zip(vertices, next_v)): + edge_vec = v1 - v0 + L = np.linalg.norm(edge_vec) + if np.isclose(L, 0.0): + continue + + # check if edge is definitely inside 2D bounds + edge_min_2d = np.minimum(v0, v1) + edge_max_2d = np.maximum(v0, v1) + definitely_inside_2d = np.all(edge_min_2d >= sim_min_2d) and np.all( + edge_max_2d <= sim_max_2d + ) + + # process each z-slice with proper clipping + for zc in z_centers: + # fast path: if edge is definitely inside 2D bounds AND z is in bounds, skip clipping + if definitely_inside_2d and z0 <= zc <= z1: + t_start, t_end = 0.0, 1.0 + else: + v0_3d = self.unpop_axis_vect(np.array([zc]), v0[None])[0] + v1_3d = self.unpop_axis_vect(np.array([zc]), v1[None])[0] - _, normal_vectors_in_plane = self.pop_axis_vect(basis_vectors["norm"]) + clip_bounds = compute_edge_clip_bounds(v0_3d, v1_3d, sim_min, sim_max) + if clip_bounds is None: + continue # edge is entirely outside bounds - vjps_edges_in_plane = vjps_edges.values.reshape((num_vertices, 1)) * normal_vectors_in_plane + t_start, t_end = clip_bounds - vjps_vertices = vjps_edges_in_plane + np.roll(vjps_edges_in_plane, axis=0, shift=1) - vjps_vertices /= 2.0 # each vertex is effected only 1/2 by each edge + s_list, s_weights = get_adaptive_samples(L, dx, t_start, t_end) - # sign change if counter clockwise, because normal direction is flipped - if self.is_ccw: - vjps_vertices *= -1 + pts2d = v0 + np.outer(s_list, edge_vec) - return vjps_vertices.real + # patch areas include quadrature weights for accurate integration + patch_areas = L * s_weights * (dz_surf if not is_2d else 1.0) + + # all points are within bounds by construction due to clipping + xyz = self.unpop_axis_vect(np.full(len(s_list), zc), pts2d) + + n_patches = len(s_list) + + # ensure we don't exceed pre-allocated size + if patch_idx + n_patches > estimated_patches: + # resize arrays if needed (rare case) + new_size = int((patch_idx + n_patches) * 1.5) + + # at this stage, no other views into these arrays exist _yet_ + # so `refcheck=False` should be safe + all_centers.resize((new_size, 3), refcheck=False) + all_areas.resize(new_size, refcheck=False) + all_normals.resize((new_size, 3), refcheck=False) + all_perps1.resize((new_size, 3), refcheck=False) + all_perps2.resize((new_size, 3), refcheck=False) + + all_centers[patch_idx : patch_idx + n_patches] = xyz + all_areas[patch_idx : patch_idx + n_patches] = patch_areas + + all_normals[patch_idx : patch_idx + n_patches] = basis["norm"][ei] + all_perps1[patch_idx : patch_idx + n_patches] = basis["perp1"][ei] + all_perps2[patch_idx : patch_idx + n_patches] = basis["perp2"][ei] + + edge_norm_2d = normals_2d[ei] + all_edge_info.extend([(ei, s_val, edge_norm_2d) for s_val in s_list]) + + patch_idx += n_patches + + if patch_idx > 0: + # trim arrays to actual size used + centers = all_centers[:patch_idx] + areas = all_areas[:patch_idx] + normals = all_normals[:patch_idx] + perps1 = all_perps1[:patch_idx] + perps2 = all_perps2[:patch_idx] + + patch_vjps = derivative_info.evaluate_gradient_at_points( + centers, normals, perps1, perps2, interpolators + ) + patch_vjps = (patch_vjps * areas).real + + for vjp, (ei, s_val, edge_norm_2d) in zip(patch_vjps, all_edge_info): + # vertex weights: (1-s) for vertex i, s for vertex i+1 + # quadrature weights are already included in areas via patch_areas + w0 = 1.0 - s_val + w1 = s_val + + vjp_per_vertex[ei] += (w0 * vjp) * edge_norm_2d + vjp_per_vertex[(ei + 1) % len(vertices)] += (w1 * vjp) * edge_norm_2d + + return vjp_per_vertex def edge_basis_vectors( self, edges: np.ndarray, # (N, 2) ) -> dict[str, np.ndarray]: # (N, 3) - """Normalized basis vectors for 'normal' direction, 'slab' tangent direction and 'edge'.""" + """Normalized basis vectors for ``normal`` direction, ``slab`` tangent direction and ``edge``.""" + + # ensure edges have consistent dtype + edges = edges.astype(GRADIENT_DTYPE_FLOAT, copy=False) num_vertices, _ = edges.shape - zeros = np.zeros(num_vertices) - ones = np.ones(num_vertices) + zeros = np.zeros(num_vertices, dtype=GRADIENT_DTYPE_FLOAT) + ones = np.ones(num_vertices, dtype=GRADIENT_DTYPE_FLOAT) # normalized vectors along edges edges_norm_in_plane = self.normalize_vect(edges) edges_norm_xyz = self.unpop_axis_vect(zeros, edges_norm_in_plane) # normalized vectors from base of edges to tops of edges - slabs_axis_components = np.cos(self.sidewall_angle) * ones - axis_norm = self.unpop_axis(1.0, (0.0, 0.0), axis=self.axis) - slab_normal_xyz = -np.sin(self.sidewall_angle) * np.cross(edges_norm_xyz, axis_norm) + cos_angle = np.cos(self.sidewall_angle, dtype=GRADIENT_DTYPE_FLOAT) + sin_angle = np.sin(self.sidewall_angle, dtype=GRADIENT_DTYPE_FLOAT) + slabs_axis_components = cos_angle * ones + + # create axis_norm as array directly to avoid tuple->array conversion in np.cross + axis_norm = np.zeros(3, dtype=GRADIENT_DTYPE_FLOAT) + axis_norm[self.axis] = 1.0 + slab_normal_xyz = -sin_angle * np.cross(edges_norm_xyz, axis_norm) _, slab_normal_in_plane = self.pop_axis_vect(slab_normal_xyz) slabs_norm_xyz = self.unpop_axis_vect(slabs_axis_components, slab_normal_in_plane) # normalized vectors pointing in normal direction of edge - normals_norm_xyz = np.cross(edges_norm_xyz, slabs_norm_xyz) - - if self.axis != 1: - normals_norm_xyz *= -1 + # cross yields inward normal when the extrusion axis is y, so negate once for axis==1 + sign = (-1 if self.axis == 1 else 1) * (-1 if not self.is_ccw else 1) + normals_norm_xyz = sign * np.cross(edges_norm_xyz, slabs_norm_xyz) - return dict(norm=normals_norm_xyz, perp1=edges_norm_xyz, perp2=slabs_norm_xyz) + return { + "norm": normals_norm_xyz, + "perp1": edges_norm_xyz, + "perp2": slabs_norm_xyz, + } def unpop_axis_vect(self, ax_coords: np.ndarray, plane_coords: np.ndarray) -> np.ndarray: """Combine coordinate along axis with coordinates on the plane tangent to the axis. @@ -1636,18 +2016,22 @@ def unpop_axis_vect(self, ax_coords: np.ndarray, plane_coords: np.ndarray) -> np ax_coords.shape == [N] plane_coords.shape == [N, 2] return shape == [N, 3] - """ - arr_xyz = self.unpop_axis(ax_coords, plane_coords.T, axis=self.axis) - arr_xyz = np.stack(arr_xyz, axis=-1) + n_pts = ax_coords.shape[0] + arr_xyz = np.zeros((n_pts, 3), dtype=ax_coords.dtype) + + plane_axes = [i for i in range(3) if i != self.axis] + + arr_xyz[:, self.axis] = ax_coords + arr_xyz[:, plane_axes] = plane_coords + return arr_xyz - def pop_axis_vect(self, coord: np.ndarray) -> Tuple[np.ndarray, Tuple[np.ndarray, np.ndarray]]: + def pop_axis_vect(self, coord: np.ndarray) -> tuple[np.ndarray, tuple[np.ndarray, np.ndarray]]: """Combine coordinate along axis with coordinates on the plane tangent to the axis. coord.shape == [N, 3] return shape == ([N], [N, 2] - """ arr_axis, arrs_plane = self.pop_axis(coord.T, axis=self.axis) @@ -1779,14 +2163,14 @@ def from_gds( cls, gds_cell, axis: Axis, - slab_bounds: Tuple[float, float], + slab_bounds: tuple[float, float], gds_layer: int, - gds_dtype: int = None, + gds_dtype: Optional[int] = None, gds_scale: pydantic.PositiveFloat = 1.0, dilation: float = 0.0, sidewall_angle: float = 0, reference_plane: PlanePosition = "middle", - ) -> List[PolySlab]: + ) -> list[PolySlab]: """Import :class:`.PolySlab` from a ``gdstk.Cell``. Parameters @@ -1855,7 +2239,7 @@ def geometry_group(self) -> base.GeometryGroup: return base.GeometryGroup(geometries=self.sub_polyslabs) @property - def sub_polyslabs(self) -> List[PolySlab]: + def sub_polyslabs(self) -> list[PolySlab]: """Divide a complex polyslab into a list of simple polyslabs. Only neighboring vertex-vertex crossing events are treated in this version. @@ -1906,11 +2290,11 @@ def sub_polyslabs(self) -> List[PolySlab]: # direction of marching reference_plane = "bottom" if dist_val / self._tanq < 0 else "top" sub_polyslab_dict.update( - dict( - slab_bounds=tuple(slab_bounds), - vertices=vertices_now, - reference_plane=reference_plane, - ) + { + "slab_bounds": tuple(slab_bounds), + "vertices": vertices_now, + "reference_plane": reference_plane, + } ) sub_polyslab_list.append(PolySlab.parse_obj(sub_polyslab_dict)) @@ -1940,7 +2324,7 @@ def sub_polyslabs(self) -> List[PolySlab]: return sub_polyslab_list @property - def _dilation_length(self) -> List[float]: + def _dilation_length(self) -> list[float]: """dilation length from reference plane to the top/bottom of the polyslab.""" # for "bottom", only needs to compute the offset length to the top @@ -1966,7 +2350,7 @@ def _dilation_value_at_reference_to_coord(self, dilation: float) -> float: def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters diff --git a/tidy3d/components/geometry/primitives.py b/tidy3d/components/geometry/primitives.py index 3b5adc69a1..193dd8466a 100644 --- a/tidy3d/components/geometry/primitives.py +++ b/tidy3d/components/geometry/primitives.py @@ -3,20 +3,22 @@ from __future__ import annotations from math import isclose -from typing import List +from typing import Optional import autograd.numpy as anp import numpy as np import pydantic.v1 as pydantic import shapely -from ...constants import C_0, LARGE_NUMBER, MICROMETER -from ...exceptions import SetupError, ValidationError -from ...packaging import verify_packages_import -from ..autograd import AutogradFieldMap, TracedSize1D -from ..autograd.derivative_utils import DerivativeInfo -from ..base import cached_property, skip_if_fields_missing -from ..types import Axis, Bound, Coordinate, MatrixReal4x4, Shapely, Tuple +from tidy3d.components.autograd import AutogradFieldMap, TracedSize1D +from tidy3d.components.autograd.constants import PTS_PER_WVL_MAT_CYLINDER_DISCRETIZE +from tidy3d.components.autograd.derivative_utils import DerivativeInfo +from tidy3d.components.base import cached_property, skip_if_fields_missing +from tidy3d.components.types import Axis, Bound, Coordinate, MatrixReal4x4, Shapely +from tidy3d.constants import C_0, LARGE_NUMBER, MICROMETER +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.packaging import verify_packages_import + from . import base from .polyslab import PolySlab @@ -29,9 +31,6 @@ # Default number of points to discretize polyslab in `Cylinder.to_polyslab()` _N_PTS_CYLINDER_POLYSLAB = 51 -# Default number of points per wvl in material for discretizing cylinder in autograd derivative -_PTS_PER_WVL_MAT_CYLINDER_DISCRETIZE = 10 - class Sphere(base.Centered, base.Circular): """Spherical geometry. @@ -71,7 +70,7 @@ def inside( def intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -110,7 +109,9 @@ def intersections_tilted_plane( vertices = np.dot(np.hstack((circ, np.ones((angles.size, 1)))), to_2D.T) return [shapely.Polygon(vertices[:, :2])] - def intersections_plane(self, x: float = None, y: float = None, z: float = None): + def intersections_plane( + self, x: Optional[float] = None, y: Optional[float] = None, z: Optional[float] = None + ): """Returns shapely geometry at plane specified by one non None value of x,y,z. Parameters @@ -277,7 +278,7 @@ def _points_unit_circle( ys = np.sin(angles) return np.stack((xs, ys), axis=0) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" # compute number of points in the circumference of the polyslab using resolution info @@ -288,17 +289,23 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM wvls_in_circumference = circumference / wvl_mat num_pts_circumference = int( - np.ceil(_PTS_PER_WVL_MAT_CYLINDER_DISCRETIZE * wvls_in_circumference) + np.ceil(PTS_PER_WVL_MAT_CYLINDER_DISCRETIZE * wvls_in_circumference) ) num_pts_circumference = max(3, num_pts_circumference) # construct equivalent polyslab and compute the derivatives polyslab = self.to_polyslab(num_pts_circumference=num_pts_circumference) - derivative_info_polyslab = derivative_info.updated_copy( - paths=[("vertices",), ("slab_bounds", 0), ("slab_bounds", 1)], deep=False - ) - vjps_polyslab = polyslab.compute_derivatives(derivative_info_polyslab) + # pass interpolators to PolySlab if available to avoid redundant conversions + update_kwargs = { + "paths": [("vertices",), ("slab_bounds", 0), ("slab_bounds", 1)], + "deep": False, + } + if derivative_info.interpolators is not None: + update_kwargs["interpolators"] = derivative_info.interpolators + + derivative_info_polyslab = derivative_info.updated_copy(**update_kwargs) + vjps_polyslab = polyslab._compute_derivatives(derivative_info_polyslab) vjps_vertices_xs, vjps_vertices_ys = vjps_polyslab[("vertices",)].T vjp_top = vjps_polyslab[("slab_bounds", 0)] @@ -354,7 +361,7 @@ def _normal_2dmaterial(self) -> Axis: raise ValidationError("'Medium2D' requires the 'Cylinder' length to be zero.") return self.axis - def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Cylinder: + def _update_from_bounds(self, bounds: tuple[float, float], axis: Axis) -> Cylinder: """Returns an updated geometry which has been transformed to fit within ``bounds`` along the ``axis`` direction.""" if axis != self.axis: @@ -370,7 +377,7 @@ def _update_from_bounds(self, bounds: Tuple[float, float], axis: Axis) -> Cylind @verify_packages_import(["trimesh"]) def _do_intersections_tilted_plane( self, normal: Coordinate, origin: Coordinate, to_2D: MatrixReal4x4 - ) -> List[Shapely]: + ) -> list[Shapely]: """Return a list of shapely geometries at the plane specified by normal and origin. Parameters @@ -461,7 +468,7 @@ def _do_intersections_tilted_plane( section = mesh.section(plane_origin=origin, plane_normal=normal) if section is None: return [] - path, _ = section.to_planar(to_2D=to_2D) + path, _ = section.to_2D(to_2D=to_2D) return path.polygons_full def _intersections_normal(self, z: float): @@ -728,7 +735,7 @@ def _radius_z(self, z: float): return radius_middle - (z - self.center_axis) * self._tanq - def _local_to_global_side_cross_section(self, coords: List[float], axis: int) -> List[float]: + def _local_to_global_side_cross_section(self, coords: list[float], axis: int) -> list[float]: """Map a point (x,y) from local to global coordinate system in the side cross section. diff --git a/tidy3d/components/geometry/triangulation.py b/tidy3d/components/geometry/triangulation.py index a6a6e00d2c..c3329c6c20 100644 --- a/tidy3d/components/geometry/triangulation.py +++ b/tidy3d/components/geometry/triangulation.py @@ -1,11 +1,12 @@ +from __future__ import annotations + from dataclasses import dataclass -from typing import List, Tuple import numpy as np import shapely -from ...exceptions import Tidy3dError -from ..types import ArrayFloat1D, ArrayFloat2D +from tidy3d.components.types import ArrayFloat1D, ArrayFloat2D +from tidy3d.exceptions import Tidy3dError @dataclass @@ -33,7 +34,7 @@ class Vertex: is_ear: bool -def update_convexity(vertices: List[Vertex], i: int) -> int: +def update_convexity(vertices: list[Vertex], i: int) -> int: """Update the convexity of a vertex in a polygon. Parameters @@ -59,9 +60,11 @@ def update_convexity(vertices: List[Vertex], i: int) -> int: """ result = -1 if vertices[i].convexity == 0.0 else 0 j = (i + 1) % len(vertices) - vertices[i].convexity = np.cross( - vertices[i].coordinate - vertices[i - 1].coordinate, - vertices[j].coordinate - vertices[i].coordinate, + vertices[i].convexity = np.linalg.det( + [ + vertices[i].coordinate - vertices[i - 1].coordinate, + vertices[j].coordinate - vertices[i].coordinate, + ] ) if vertices[i].convexity == 0.0: result += 1 @@ -69,7 +72,7 @@ def update_convexity(vertices: List[Vertex], i: int) -> int: def is_inside( - vertex: ArrayFloat1D, triangle: Tuple[ArrayFloat1D, ArrayFloat1D, ArrayFloat1D] + vertex: ArrayFloat1D, triangle: tuple[ArrayFloat1D, ArrayFloat1D, ArrayFloat1D] ) -> bool: """Check if a vertex is inside a triangle. @@ -86,11 +89,12 @@ def is_inside( Flag indicating if the vertex is inside the triangle. """ return all( - np.cross(triangle[i] - triangle[i - 1], vertex - triangle[i - 1]) > 0 for i in range(3) + np.linalg.det([triangle[i] - triangle[i - 1], vertex - triangle[i - 1]]) > 0 + for i in range(3) ) -def update_ear_flag(vertices: List[Vertex], i: int) -> None: +def update_ear_flag(vertices: list[Vertex], i: int) -> None: """Update the ear flag of a vertex in a polygon. Parameters @@ -112,7 +116,7 @@ def update_ear_flag(vertices: List[Vertex], i: int) -> None: # TODO: This is an inefficient algorithm that runs in O(n^2). We should use something # better, and probably as a compiled extension. -def triangulate(vertices: ArrayFloat2D) -> List[Tuple[int, int, int]]: +def triangulate(vertices: ArrayFloat2D) -> list[tuple[int, int, int]]: """Triangulate a simple polygon. Parameters diff --git a/tidy3d/components/geometry/utils.py b/tidy3d/components/geometry/utils.py index 9eaa7542e3..8c166fdd21 100644 --- a/tidy3d/components/geometry/utils.py +++ b/tidy3d/components/geometry/utils.py @@ -4,17 +4,25 @@ from enum import Enum from math import isclose -from typing import Any, List, Optional, Tuple, Union +from typing import Any, Optional, Union import numpy as np -import pydantic as pydantic - -from ...constants import fp_eps -from ...exceptions import SetupError, Tidy3dError -from ..base import Tidy3dBaseModel -from ..geometry.base import Box -from ..grid.grid import Grid -from ..types import ArrayFloat2D, Axis, Coordinate, MatrixReal4x4, PlanePosition, Shapely +import pydantic + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.geometry.base import Box +from tidy3d.components.grid.grid import Grid +from tidy3d.components.types import ( + ArrayFloat2D, + Axis, + Coordinate, + MatrixReal4x4, + PlanePosition, + Shapely, +) +from tidy3d.constants import fp_eps +from tidy3d.exceptions import SetupError, Tidy3dError + from . import base, mesh, polyslab, primitives GeometryType = Union[ @@ -31,10 +39,10 @@ def merging_geometries_on_plane( - geometries: List[GeometryType], + geometries: list[GeometryType], plane: Box, - property_list: List[Any], -) -> List[Tuple[Any, Shapely]]: + property_list: list[Any], +) -> list[tuple[Any, Shapely]]: """Compute list of shapes on plane. Overlaps are removed or merged depending on provided property_list. @@ -191,7 +199,7 @@ def traverse_geometries(geometry: GeometryType) -> GeometryType: def from_shapely( shape: Shapely, axis: Axis, - slab_bounds: Tuple[float, float], + slab_bounds: tuple[float, float], dilation: float = 0.0, sidewall_angle: float = 0, reference_plane: PlanePosition = "middle", @@ -284,7 +292,7 @@ def vertices_from_shapely(shape: Shapely) -> ArrayFloat2D: if shape.geom_type == "LinearRing": return [(shape.coords[:-1],)] if shape.geom_type == "Polygon": - return [(shape.exterior.coords[:-1],) + tuple(hole.coords[:-1] for hole in shape.interiors)] + return [(shape.exterior.coords[:-1], *tuple(hole.coords[:-1] for hole in shape.interiors))] if shape.geom_type in {"MultiPolygon", "GeometryCollection"}: return sum(vertices_from_shapely(geo) for geo in shape.geoms) diff --git a/tidy3d/components/geometry/utils_2d.py b/tidy3d/components/geometry/utils_2d.py index 5d7b0860f9..46b238accd 100644 --- a/tidy3d/components/geometry/utils_2d.py +++ b/tidy3d/components/geometry/utils_2d.py @@ -1,18 +1,19 @@ """Utilities for 2D geometry manipulation.""" +from __future__ import annotations + from math import isclose -from typing import List, Tuple import numpy as np import shapely -from ...constants import fp_eps, inf -from ..geometry.base import Box, ClipOperation, Geometry -from ..geometry.polyslab import _MIN_POLYGON_AREA, PolySlab -from ..grid.grid import Grid -from ..scene import Scene -from ..structure import Structure -from ..types import Axis +from tidy3d.components.geometry.base import Box, ClipOperation, Geometry +from tidy3d.components.geometry.polyslab import _MIN_POLYGON_AREA, PolySlab +from tidy3d.components.grid.grid import Grid +from tidy3d.components.scene import Scene +from tidy3d.components.structure import Structure +from tidy3d.components.types import Axis +from tidy3d.constants import fp_eps, inf def increment_float(val: float, sign) -> float: @@ -46,7 +47,7 @@ def snap_coordinate_to_grid(grid: Grid, center: float, axis: Axis) -> float: return new_center -def get_bounds(geom: Geometry, axis: Axis) -> Tuple[float, float]: +def get_bounds(geom: Geometry, axis: Axis) -> tuple[float, float]: """Get the bounds of a geometry in the axis direction.""" return (geom.bounds[0][axis], geom.bounds[1][axis]) @@ -62,7 +63,7 @@ def get_thickened_geom(geom: Geometry, axis: Axis): def get_neighbors( geom: Geometry, axis: Axis, - structures: List[Structure], + structures: list[Structure], ): """Find the neighboring structures and return the tested positions above and below.""" center = get_bounds(geom, axis)[0] @@ -100,8 +101,8 @@ def get_neighbors( def subdivide( - geom: Geometry, structures: List[Structure] -) -> List[Tuple[Geometry, Structure, Structure]]: + geom: Geometry, structures: list[Structure] +) -> list[tuple[Geometry, Structure, Structure]]: """Subdivide geometry associated with a :class:`.Medium2D` into partitions that each have a homogeneous substrate / superstrate. Partitions are computed using ``shapely`` boolean operations on polygons. diff --git a/tidy3d/components/grid/corner_finder.py b/tidy3d/components/grid/corner_finder.py index ccd301a18d..272aa28131 100644 --- a/tidy3d/components/grid/corner_finder.py +++ b/tidy3d/components/grid/corner_finder.py @@ -1,17 +1,19 @@ """Find corners of structures on a 2D plane.""" -from typing import List, Literal, Optional +from __future__ import annotations + +from typing import Any, Literal, Optional import numpy as np import pydantic.v1 as pd -from ...constants import inf -from ..base import Tidy3dBaseModel -from ..geometry.base import Box, ClipOperation -from ..geometry.utils import merging_geometries_on_plane -from ..medium import PEC, LossyMetalMedium -from ..structure import Structure -from ..types import ArrayFloat2D, Axis +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.geometry.base import Box, ClipOperation +from tidy3d.components.geometry.utils import merging_geometries_on_plane +from tidy3d.components.medium import PEC, LossyMetalMedium +from tidy3d.components.structure import Structure +from tidy3d.components.types import ArrayFloat1D, ArrayFloat2D, Axis, Shapely +from tidy3d.constants import inf CORNER_ANGLE_THRESOLD = 0.1 * np.pi @@ -44,15 +46,47 @@ class CornerFinderSpec(Tidy3dBaseModel): "is below the threshold value based on Douglas-Peucker algorithm, the vertex is disqualified as a corner.", ) - def corners( - self, + concave_resolution: Optional[pd.PositiveInt] = pd.Field( + None, + title="Concave Region Resolution.", + description="Specifies number of steps to use for determining `dl_min` based on concave featues." + "If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + ) + + convex_resolution: Optional[pd.PositiveInt] = pd.Field( + None, + title="Convex Region Resolution.", + description="Specifies number of steps to use for determining `dl_min` based on convex featues." + "If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + ) + + mixed_resolution: Optional[pd.PositiveInt] = pd.Field( + None, + title="Mixed Region Resolution.", + description="Specifies number of steps to use for determining `dl_min` based on mixed featues." + "If set to ``None``, then the corresponding `dl_min` reduction is not applied.", + ) + + @cached_property + def _no_min_dl_override(self): + return all( + ( + self.concave_resolution is None, + self.convex_resolution is None, + self.mixed_resolution is None, + ) + ) + + @classmethod + def _merged_pec_on_plane( + cls, normal_axis: Axis, coord: float, - structure_list: List[Structure], - ) -> ArrayFloat2D: - """On a 2D plane specified by axis = `normal_axis` and coordinate `coord`, find out corners of merged - geometries made of `medium`. - + structure_list: list[Structure], + center: tuple[float, float] = [0, 0, 0], + size: tuple[float, float, float] = [inf, inf, inf], + ) -> list[tuple[Any, Shapely]]: + """On a 2D plane specified by axis = `normal_axis` and coordinate `coord`, merge geometries made of PEC. Parameters ---------- @@ -62,19 +96,23 @@ def corners( Position of plane along the normal axis. structure_list : List[Structure] List of structures present in simulation. + center : Tuple[float, float] = [0, 0, 0] + Center of the 2D plane (coordinate along ``axis`` is ignored) + size : Tuple[float, float, float] = [inf, inf, inf] + Size of the 2D plane (size along ``axis`` is ignored) Returns ------- - ArrayFloat2D - Corner coordinates. + List[Tuple[Any, Shapely]] + List of shapes and their property value on the plane after merging. """ # Construct plane - center = [0, 0, 0] - size = [inf, inf, inf] - center[normal_axis] = coord - size[normal_axis] = 0 - plane = Box(center=center, size=size) + slice_center = list(center) + slice_size = list(size) + slice_center[normal_axis] = coord + slice_size[normal_axis] = 0 + plane = Box(center=slice_center, size=slice_size) # prepare geometry and medium list geometry_list = [structure.geometry for structure in structure_list] @@ -87,8 +125,44 @@ def corners( # merge geometries merged_geos = merging_geometries_on_plane(geometry_list, plane, medium_list) + return merged_geos + + def _corners_and_convexity( + self, + normal_axis: Axis, + coord: float, + structure_list: list[Structure], + ravel: bool, + ) -> tuple[ArrayFloat2D, ArrayFloat1D]: + """On a 2D plane specified by axis = `normal_axis` and coordinate `coord`, find out corners of merged + geometries made of PEC. + + + Parameters + ---------- + normal_axis : Axis + Axis normal to the 2D plane. + coord : float + Position of plane along the normal axis. + structure_list : List[Structure] + List of structures present in simulation. + ravel : bool + Whether to put the resulting corners in a single list or per polygon. + + Returns + ------- + Tuple[ArrayFloat2D, ArrayFloat1D] + Corner coordinates and their convexity. + """ + + # merge geometries + merged_geos = self._merged_pec_on_plane( + normal_axis=normal_axis, coord=coord, structure_list=structure_list + ) + # corner finder corner_list = [] + convexity_list = [] for mat, shapes in merged_geos: if self.medium != "all" and mat.is_pec != (self.medium == "metal"): continue @@ -97,17 +171,59 @@ def corners( poly = poly.normalize().buffer(0) if self.distance_threshold is not None: poly = poly.simplify(self.distance_threshold, preserve_topology=True) - corner_list.append(self._filter_collinear_vertices(list(poly.exterior.coords))) + corners_xy, corners_convexity = self._filter_collinear_vertices( + list(poly.exterior.coords) + ) + corner_list.append(corners_xy) + convexity_list.append(corners_convexity) # in case the polygon has holes for poly_inner in poly.interiors: - corner_list.append(self._filter_collinear_vertices(list(poly_inner.coords))) + corners_xy, corners_convexity = self._filter_collinear_vertices( + list(poly_inner.coords) + ) + corner_list.append(corners_xy) + convexity_list.append(corners_convexity) - if len(corner_list) > 0: + if ravel and len(corner_list) > 0: corner_list = np.concatenate(corner_list) + convexity_list = np.concatenate(convexity_list) + + return corner_list, convexity_list + + def corners( + self, + normal_axis: Axis, + coord: float, + structure_list: list[Structure], + ) -> ArrayFloat2D: + """On a 2D plane specified by axis = `normal_axis` and coordinate `coord`, find out corners of merged + geometries made of `medium`. + + + Parameters + ---------- + normal_axis : Axis + Axis normal to the 2D plane. + coord : float + Position of plane along the normal axis. + structure_list : List[Structure] + List of structures present in simulation. + + Returns + ------- + ArrayFloat2D + Corner coordinates. + """ + + corner_list, _ = self._corners_and_convexity( + normal_axis=normal_axis, coord=coord, structure_list=structure_list, ravel=True + ) return corner_list - def _filter_collinear_vertices(self, vertices: ArrayFloat2D) -> ArrayFloat2D: - """Filter collinear vertices of a polygon, and return corners. + def _filter_collinear_vertices( + self, vertices: ArrayFloat2D + ) -> tuple[ArrayFloat2D, ArrayFloat1D]: + """Filter collinear vertices of a polygon, and return corners locations and their convexity. Parameters ---------- @@ -119,6 +235,8 @@ def _filter_collinear_vertices(self, vertices: ArrayFloat2D) -> ArrayFloat2D: ------- ArrayFloat2D Corner coordinates. + ArrayFloat1D + Convexity of corners: True for outer corners, False for inner corners. """ def normalize(v): @@ -136,5 +254,12 @@ def normalize(v): inner_product = np.where(inner_product > 1, 1, inner_product) inner_product = np.where(inner_product < -1, -1, inner_product) angle = np.arccos(inner_product) + num_vs = len(vs_orig) + cross_product = np.cross( + np.hstack([unit_next, np.zeros((num_vs, 1))]), + np.hstack([unit_previous, np.zeros((num_vs, 1))]), + axis=-1, + ) + convexity = cross_product[:, 2] < 0 ind_filter = angle <= np.pi - self.angle_threshold - return vs_orig[ind_filter] + return vs_orig[ind_filter], convexity[ind_filter] diff --git a/tidy3d/components/grid/grid.py b/tidy3d/components/grid/grid.py index 62353b659e..5baf3828e0 100644 --- a/tidy3d/components/grid/grid.py +++ b/tidy3d/components/grid/grid.py @@ -2,17 +2,17 @@ from __future__ import annotations -from typing import Dict, List, Tuple, Union +from typing import Literal, Union import numpy as np import pydantic.v1 as pd -from ...exceptions import SetupError -from ..base import Tidy3dBaseModel, cached_property -from ..data.data_array import DataArray, ScalarFieldDataArray, SpatialDataArray -from ..data.utils import UnstructuredGridDataset, UnstructuredGridDatasetType -from ..geometry.base import Box -from ..types import ArrayFloat1D, Axis, Coordinate, InterpMethod, Literal +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.data.data_array import DataArray, ScalarFieldDataArray, SpatialDataArray +from tidy3d.components.data.utils import UnstructuredGridDataset, UnstructuredGridDatasetType +from tidy3d.components.geometry.base import Box +from tidy3d.components.types import ArrayFloat1D, Axis, Coordinate, InterpMethod +from tidy3d.exceptions import SetupError # data type of one dimensional coordinate array. Coords1D = ArrayFloat1D @@ -84,7 +84,7 @@ def cell_size_meshgrid(self): if len(meshgrid_elements) > 1: meshgrid = np.meshgrid(*meshgrid_elements, indexing="ij") - for idx in range(0, len(meshgrid)): + for idx in range(len(meshgrid)): cell_size_meshgrid *= np.reshape(meshgrid[idx], cell_size_meshgrid.shape) elif len(meshgrid_elements) == 1: cell_size_meshgrid = meshgrid_elements[0] @@ -262,10 +262,9 @@ def spatial_interp( return self._interp_from_unstructured( array=array, interp_method=interp_method, fill_value=fill_value ) - else: - return self._interp_from_xarray( - array=array, interp_method=interp_method, fill_value=fill_value - ) + return self._interp_from_xarray( + array=array, interp_method=interp_method, fill_value=fill_value + ) class FieldGrid(Tidy3dBaseModel): @@ -410,7 +409,7 @@ def sizes(self) -> Coords: return Coords(**{key: np.diff(val) for key, val in self.boundaries.to_dict.items()}) @property - def num_cells(self) -> Tuple[int, int, int]: + def num_cells(self) -> tuple[int, int, int]: """Return sizes of the cells in the :class:`Grid`. Returns @@ -452,7 +451,7 @@ def max_size(self) -> float: return float(max(max(sizes) for sizes in self.sizes.to_list)) @property - def info(self) -> Dict: + def info(self) -> dict: """Dictionary collecting various properties of the grids.""" num_cells = self.num_cells total_cells = int(np.prod(num_cells)) @@ -567,7 +566,7 @@ def _yee_h(self, axis: Axis): return Coords(**yee_coords) - def discretize_inds(self, box: Box, extend: bool = False) -> List[Tuple[int, int]]: + def discretize_inds(self, box: Box, extend: bool = False) -> list[tuple[int, int]]: """Start and stopping indexes for the cells that intersect with a :class:`Box`. Parameters diff --git a/tidy3d/components/grid/grid_spec.py b/tidy3d/components/grid/grid_spec.py index 469560700d..10b4d0e38d 100644 --- a/tidy3d/components/grid/grid_spec.py +++ b/tidy3d/components/grid/grid_spec.py @@ -3,28 +3,31 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, List, Literal, Optional, Tuple, Union +from typing import Any, Literal, Optional, Union import numpy as np import pydantic.v1 as pd -from ...constants import C_0, MICROMETER, inf -from ...exceptions import SetupError -from ...log import log -from ..base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ..geometry.base import Box -from ..lumped_element import LumpedElementType -from ..source.utils import SourceType -from ..structure import MeshOverrideStructure, Structure, StructureType -from ..types import ( +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.geometry.base import Box, ClipOperation +from tidy3d.components.lumped_element import LumpedElementType +from tidy3d.components.source.utils import SourceType +from tidy3d.components.structure import MeshOverrideStructure, Structure, StructureType +from tidy3d.components.types import ( TYPE_TAG_STR, ArrayFloat2D, Axis, Coordinate, CoordinateOptional, + PriorityMode, Symmetry, + Undefined, annotate_type, ) +from tidy3d.constants import C_0, MICROMETER, dp_eps, inf +from tidy3d.exceptions import SetupError +from tidy3d.log import log + from .corner_finder import CornerFinderSpec from .grid import Coords, Coords1D, Grid from .mesher import GradedMesher, MesherType @@ -36,6 +39,9 @@ # Default refinement factor in GridRefinement when both dl and refinement_factor are not defined DEFAULT_REFINEMENT_FACTOR = 2 +# Tolerance for distinguishing pec/grid intersections +GAP_MESHING_TOL = 1e-3 + class GridSpec1d(Tidy3dBaseModel, ABC): """Abstract base class, defines 1D grid generation specifications.""" @@ -43,12 +49,12 @@ class GridSpec1d(Tidy3dBaseModel, ABC): def make_coords( self, axis: Axis, - structures: List[StructureType], - symmetry: Tuple[Symmetry, Symmetry, Symmetry], + structures: list[StructureType], + symmetry: tuple[Symmetry, Symmetry, Symmetry], periodic: bool, wavelength: pd.PositiveFloat, - num_pml_layers: Tuple[pd.NonNegativeInt, pd.NonNegativeInt], - snapping_points: Tuple[CoordinateOptional, ...], + num_pml_layers: tuple[pd.NonNegativeInt, pd.NonNegativeInt], + snapping_points: tuple[CoordinateOptional, ...], ) -> Coords1D: """Generate 1D coords to be used as grid boundaries, based on simulation parameters. Symmetry, and PML layers will be treated here. @@ -62,6 +68,9 @@ def make_coords( symmetry : Tuple[Symmetry, Symmetry, Symmetry] Reflection symmetry across a plane bisecting the simulation domain normal to each of the three axes. + periodic : bool + Apply periodic boundary condition or not. + Only relevant for autogrids. wavelength : float Free-space wavelength. num_pml_layers : Tuple[int, int] @@ -106,7 +115,7 @@ def make_coords( def _make_coords_initial( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], **kwargs, ) -> Coords1D: """Generate 1D coords to be used as grid boundaries, based on simulation parameters. @@ -128,7 +137,7 @@ def _make_coords_initial( """ @staticmethod - def _add_pml_to_bounds(num_layers: Tuple[int, int], bounds: Coords1D) -> Coords1D: + def _add_pml_to_bounds(num_layers: tuple[int, int], bounds: Coords1D) -> Coords1D: """Append absorber layers to the beginning and end of the simulation bounds along one dimension. @@ -203,31 +212,30 @@ def _postprocess_unaligned_grid( return bound_coords[ind - 1 : ind + 1] - else: - bound_coords = bound_coords[bound_coords <= bound_max] - bound_coords = bound_coords[bound_coords >= bound_min] - - # if not extending to simulation bounds, repeat beginning and end - dl_min = bound_coords[1] - bound_coords[0] - dl_max = bound_coords[-1] - bound_coords[-2] - while bound_coords[0] - dl_min >= bound_min: + bound_coords = bound_coords[bound_coords <= bound_max] + bound_coords = bound_coords[bound_coords >= bound_min] + + # if not extending to simulation bounds, repeat beginning and end + dl_min = bound_coords[1] - bound_coords[0] + dl_max = bound_coords[-1] - bound_coords[-2] + while bound_coords[0] - dl_min >= bound_min: + bound_coords = np.insert(bound_coords, 0, bound_coords[0] - dl_min) + while bound_coords[-1] + dl_max <= bound_max: + bound_coords = np.append(bound_coords, bound_coords[-1] + dl_max) + + # in case operations are applied to coords, it's possible the bounds were numerically within + # the simulation bounds but were still chopped off, which is fixed here + if machine_error_relaxation: + if np.isclose(bound_coords[0] - dl_min, bound_min): bound_coords = np.insert(bound_coords, 0, bound_coords[0] - dl_min) - while bound_coords[-1] + dl_max <= bound_max: + if np.isclose(bound_coords[-1] + dl_max, bound_max): bound_coords = np.append(bound_coords, bound_coords[-1] + dl_max) - # in case operations are applied to coords, it's possible the bounds were numerically within - # the simulation bounds but were still chopped off, which is fixed here - if machine_error_relaxation: - if np.isclose(bound_coords[0] - dl_min, bound_min): - bound_coords = np.insert(bound_coords, 0, bound_coords[0] - dl_min) - if np.isclose(bound_coords[-1] + dl_max, bound_max): - bound_coords = np.append(bound_coords, bound_coords[-1] + dl_max) - - return bound_coords + return bound_coords @abstractmethod def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Estimated minimal grid size along the axis. The actual minimal grid size from mesher might be smaller. @@ -292,7 +300,7 @@ def _validate_dl(cls, val): def _make_coords_initial( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], **kwargs, ) -> Coords1D: """Uniform 1D coords to be used as grid boundaries. @@ -324,7 +332,7 @@ def _make_coords_initial( return center - size / 2 + np.arange(num_cells + 1) * dl_snapped def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Minimal grid size, which equals grid size here. @@ -364,7 +372,7 @@ class CustomGridBoundaries(GridSpec1d): def _make_coords_initial( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], **kwargs, ) -> Coords1D: """Customized 1D coords to be used as grid boundaries. @@ -390,7 +398,7 @@ def _make_coords_initial( ) def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Minimal grid size from grid specification. @@ -411,6 +419,23 @@ def estimated_min_dl( return min(np.diff(self.coords)) + @pd.validator("coords", always=True) + def _validate_coords(cls, val): + """ + Ensure 'coords' is sorted and has at least 2 entries. + """ + if len(val) < 2: + raise SetupError("You must supply at least 2 entries for 'coords'.") + # Ensure coords is sorted + positive_diff = np.diff(val) > 0 + if not np.all(positive_diff): + violations = np.where(np.diff(val) <= 0)[0] + 1 + raise SetupError( + "'coords' must be strictly increasing (sorted in ascending order). " + f"The entries at the following indices violated this requirement: {violations}." + ) + return val + class CustomGrid(GridSpec1d): """Custom 1D grid supplied as a list of grid cell sizes centered on the simulation center. @@ -420,7 +445,7 @@ class CustomGrid(GridSpec1d): >>> grid_1d = CustomGrid(dl=[0.2, 0.2, 0.1, 0.1, 0.1, 0.2, 0.2]) """ - dl: Tuple[pd.PositiveFloat, ...] = pd.Field( + dl: tuple[pd.PositiveFloat, ...] = pd.Field( ..., title="Customized grid sizes.", description="An array of custom nonuniform grid sizes. The resulting grid is centered on " @@ -443,7 +468,7 @@ class CustomGrid(GridSpec1d): def _make_coords_initial( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], **kwargs, ) -> Coords1D: """Customized 1D coords to be used as grid boundaries. @@ -482,7 +507,7 @@ def _make_coords_initial( ) def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Minimal grid size from grid specification. @@ -532,11 +557,11 @@ class AbstractAutoGrid(GridSpec1d): ) @abstractmethod - def _preprocessed_structures(self, structures: List[StructureType]) -> List[StructureType]: + def _preprocessed_structures(self, structures: list[StructureType]) -> list[StructureType]: """Preprocess structure list before passing to ``mesher``.""" @abstractmethod - def _dl_collapsed_axis(self, wavelength: float, sim_size: Tuple[float, 3]) -> float: + def _dl_collapsed_axis(self, wavelength: float, sim_size: tuple[float, 3]) -> float: """The grid step size if just a single grid along an axis in the simulation domain.""" @property @@ -550,7 +575,7 @@ def _min_steps_per_wvl(self) -> float: """Minimal steps per wavelength applied internally.""" @abstractmethod - def _dl_max(self, sim_size: Tuple[float, 3]) -> float: + def _dl_max(self, sim_size: tuple[float, 3]) -> float: """Upper bound of grid size applied internally.""" @property @@ -558,18 +583,18 @@ def _undefined_dl_min(self) -> bool: """Whether `dl_min` has been specified or not.""" return self.dl_min is None or self.dl_min == 0 - def _filtered_dl(self, dl: float, sim_size: Tuple[float, 3]) -> float: + def _filtered_dl(self, dl: float, sim_size: tuple[float, 3]) -> float: """Grid step size after applying minimal and maximal filtering.""" return max(min(dl, self._dl_max(sim_size)), self._dl_min) def _make_coords_initial( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], wavelength: float, symmetry: Symmetry, is_periodic: bool, - snapping_points: Tuple[CoordinateOptional, ...], + snapping_points: tuple[CoordinateOptional, ...], ) -> Coords1D: """Customized 1D coords to be used as grid boundaries. @@ -697,7 +722,7 @@ class QuasiUniformGrid(AbstractAutoGrid): units=MICROMETER, ) - def _preprocessed_structures(self, structures: List[StructureType]) -> List[StructureType]: + def _preprocessed_structures(self, structures: list[StructureType]) -> list[StructureType]: """Processing structure list before passing to ``mesher``. Adjust all structures to drop their material properties so that they all have step size ``dl``. """ @@ -725,16 +750,16 @@ def _min_steps_per_wvl(self) -> float: # irrelevant in this class, just supply an arbitrary number return 1 - def _dl_max(self, sim_size: Tuple[float, 3]) -> float: + def _dl_max(self, sim_size: tuple[float, 3]) -> float: """Upper bound of grid size.""" return self.dl - def _dl_collapsed_axis(self, wavelength: float, sim_size: Tuple[float, 3]) -> float: + def _dl_collapsed_axis(self, wavelength: float, sim_size: tuple[float, 3]) -> float: """The grid step size if just a single grid along an axis.""" return self._filtered_dl(self.dl, sim_size) def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Estimated minimal grid size, which equals grid size here. @@ -795,7 +820,7 @@ class AutoGrid(AbstractAutoGrid): ge=1.0, ) - def _dl_max(self, sim_size: Tuple[float, 3]) -> float: + def _dl_max(self, sim_size: tuple[float, 3]) -> float: """Upper bound of grid size, constrained by `min_steps_per_sim_size`.""" return max(sim_size) / self.min_steps_per_sim_size @@ -812,20 +837,20 @@ def _min_steps_per_wvl(self) -> float: """Minimal steps per wavelength.""" return self.min_steps_per_wvl - def _preprocessed_structures(self, structures: List[StructureType]) -> List[StructureType]: + def _preprocessed_structures(self, structures: list[StructureType]) -> list[StructureType]: """Processing structure list before passing to ``mesher``.""" return structures - def _dl_collapsed_axis(self, wavelength: float, sim_size: Tuple[float, 3]) -> float: + def _dl_collapsed_axis(self, wavelength: float, sim_size: tuple[float, 3]) -> float: """The grid step size if just a single grid along an axis.""" return self._vacuum_dl(wavelength, sim_size) - def _vacuum_dl(self, wavelength: float, sim_size: Tuple[float, 3]) -> float: + def _vacuum_dl(self, wavelength: float, sim_size: tuple[float, 3]) -> float: """Grid step size when computed in vacuum region.""" return self._filtered_dl(wavelength / self.min_steps_per_wvl, sim_size) def estimated_min_dl( - self, wavelength: float, structure_list: List[Structure], sim_size: Tuple[float, 3] + self, wavelength: float, structure_list: list[Structure], sim_size: tuple[float, 3] ) -> float: """Estimated minimal grid size along the axis. The actual minimal grid size from mesher might be smaller. @@ -953,6 +978,7 @@ def override_structure( dl=dl_list, shadow=False, drop_outside_sim=drop_outside_sim, + priority=-1, ) @@ -1037,6 +1063,20 @@ class LayerRefinementSpec(Box): "and the projection of the simulation domain overlaps.", ) + gap_meshing_iters: pd.NonNegativeInt = pd.Field( + 1, + title="Gap Meshing Iterations", + description="Number of recursive iterations for resolving thin gaps. " + "The underlying algorithm detects gaps contained in a single cell and places a snapping plane at the gaps's centers.", + ) + + dl_min_from_gap_width: bool = pd.Field( + True, + title="Set ``dl_min`` from Estimated Gap Width", + description="Take into account autodetected minimal PEC gap width when determining ``dl_min``. " + "This only applies if ``dl_min`` in ``AutoGrid`` specification is not set.", + ) + @pd.validator("axis", always=True) @skip_if_fields_missing(["size"]) def _finite_size_along_axis(cls, val, values): @@ -1049,14 +1089,16 @@ def _finite_size_along_axis(cls, val, values): def from_layer_bounds( cls, axis: Axis, - bounds: Tuple[float, float], + bounds: tuple[float, float], min_steps_along_axis: np.PositiveFloat = None, bounds_refinement: GridRefinement = None, bounds_snapping: Literal["bounds", "lower", "upper", "center"] = "lower", - corner_finder: CornerFinderSpec = CornerFinderSpec(), + corner_finder: Union[CornerFinderSpec, None, object] = Undefined, corner_snapping: bool = True, - corner_refinement: GridRefinement = GridRefinement(), + corner_refinement: Union[GridRefinement, None, object] = Undefined, refinement_inside_sim_only: bool = True, + gap_meshing_iters: pd.NonNegativeInt = 1, + dl_min_from_gap_width: bool = True, ): """Constructs a :class:`LayerRefiementSpec` that is unbounded in inplane dimensions from bounds along layer thickness dimension. @@ -1082,6 +1124,10 @@ def from_layer_bounds( Inplane mesh refinement factor around corners. refinement_inside_sim_only : bool = True Apply refinement only to features inside simulation domain. + gap_meshing_iters : bool = True + Number of recursive iterations for resolving thin gaps. + dl_min_from_gap_width : bool = True + Take into account autodetected minimal PEC gap width when determining ``dl_min``. Example @@ -1089,6 +1135,11 @@ def from_layer_bounds( >>> layer = LayerRefinementSpec.from_layer_bounds(axis=2, bounds=(0,1)) """ + if corner_finder is Undefined: + corner_finder = CornerFinderSpec() + if corner_refinement is Undefined: + corner_refinement = GridRefinement() + center = Box.unpop_axis((bounds[0] + bounds[1]) / 2, (0, 0), axis) size = Box.unpop_axis((bounds[1] - bounds[0]), (inf, inf), axis) @@ -1103,6 +1154,8 @@ def from_layer_bounds( corner_snapping=corner_snapping, corner_refinement=corner_refinement, refinement_inside_sim_only=refinement_inside_sim_only, + gap_meshing_iters=gap_meshing_iters, + dl_min_from_gap_width=dl_min_from_gap_width, ) @classmethod @@ -1114,10 +1167,12 @@ def from_bounds( min_steps_along_axis: np.PositiveFloat = None, bounds_refinement: GridRefinement = None, bounds_snapping: Literal["bounds", "lower", "upper", "center"] = "lower", - corner_finder: CornerFinderSpec = CornerFinderSpec(), + corner_finder: CornerFinderSpec = Undefined, corner_snapping: bool = True, - corner_refinement: GridRefinement = GridRefinement(), + corner_refinement: GridRefinement = Undefined, refinement_inside_sim_only: bool = True, + gap_meshing_iters: pd.NonNegativeInt = 1, + dl_min_from_gap_width: bool = True, ): """Constructs a :class:`LayerRefiementSpec` from minimum and maximum coordinate bounds. @@ -1145,6 +1200,10 @@ def from_bounds( Inplane mesh refinement factor around corners. refinement_inside_sim_only : bool = True Apply refinement only to features inside simulation domain. + gap_meshing_iters : bool = True + Number of recursive iterations for resolving thin gaps. + dl_min_from_gap_width : bool = True + Take into account autodetected minimal PEC gap width when determining ``dl_min``. Example @@ -1152,6 +1211,11 @@ def from_bounds( >>> layer = LayerRefinementSpec.from_bounds(axis=2, rmin=(0,0,0), rmax=(1,1,1)) """ + if corner_finder is Undefined: + corner_finder = CornerFinderSpec() + if corner_refinement is Undefined: + corner_refinement = GridRefinement() + box = Box.from_bounds(rmin=rmin, rmax=rmax) if axis is None: axis = np.argmin(box.size) @@ -1166,20 +1230,24 @@ def from_bounds( corner_snapping=corner_snapping, corner_refinement=corner_refinement, refinement_inside_sim_only=refinement_inside_sim_only, + gap_meshing_iters=gap_meshing_iters, + dl_min_from_gap_width=dl_min_from_gap_width, ) @classmethod def from_structures( cls, - structures: List[Structure], + structures: list[Structure], axis: Axis = None, min_steps_along_axis: np.PositiveFloat = None, bounds_refinement: GridRefinement = None, bounds_snapping: Literal["bounds", "lower", "upper", "center"] = "lower", - corner_finder: CornerFinderSpec = CornerFinderSpec(), + corner_finder: CornerFinderSpec = Undefined, corner_snapping: bool = True, - corner_refinement: GridRefinement = GridRefinement(), + corner_refinement: GridRefinement = Undefined, refinement_inside_sim_only: bool = True, + gap_meshing_iters: pd.NonNegativeInt = 1, + dl_min_from_gap_width: bool = True, ): """Constructs a :class:`LayerRefiementSpec` from the bounding box of a list of structures. @@ -1205,8 +1273,16 @@ def from_structures( Inplane mesh refinement factor around corners. refinement_inside_sim_only : bool = True Apply refinement only to features inside simulation domain. + gap_meshing_iters : bool = True + Number of recursive iterations for resolving thin gaps. + dl_min_from_gap_width : bool = True + Take into account autodetected minimal PEC gap width when determining ``dl_min``. """ + if corner_finder is Undefined: + corner_finder = CornerFinderSpec() + if corner_refinement is Undefined: + corner_refinement = GridRefinement() all_bounds = tuple(structure.geometry.bounds for structure in structures) rmin = tuple(min(b[i] for b, _ in all_bounds) for i in range(3)) @@ -1226,6 +1302,8 @@ def from_structures( corner_snapping=corner_snapping, corner_refinement=corner_refinement, refinement_inside_sim_only=refinement_inside_sim_only, + gap_meshing_iters=gap_meshing_iters, + dl_min_from_gap_width=dl_min_from_gap_width, ) @cached_property @@ -1262,7 +1340,7 @@ def _unpop_axis(self, ax_coord: float, plane_coord: Any) -> CoordinateOptional: """ return self.unpop_axis(ax_coord, [plane_coord, plane_coord], self.axis) - def suggested_dl_min(self, grid_size_in_vacuum: float) -> float: + def suggested_dl_min(self, grid_size_in_vacuum: float, structures: list[Structure]) -> float: """Suggested lower bound of grid step size for this layer. Parameters @@ -1293,9 +1371,15 @@ def suggested_dl_min(self, grid_size_in_vacuum: float) -> float: # inplane dimension if self.corner_finder is not None and self.corner_refinement is not None: dl_min = min(dl_min, self.corner_refinement._grid_size(grid_size_in_vacuum)) + + # min feature size + if self.corner_finder is not None and not self.corner_finder._no_min_dl_override: + dl_suggested = self._dl_min_from_smallest_feature(structures) + dl_min = min(dl_min, dl_suggested) + return dl_min - def generate_snapping_points(self, structure_list: List[Structure]) -> List[CoordinateOptional]: + def generate_snapping_points(self, structure_list: list[Structure]) -> list[CoordinateOptional]: """generate snapping points for mesh refinement.""" snapping_points = self._snapping_points_along_axis if self.corner_snapping: @@ -1303,8 +1387,8 @@ def generate_snapping_points(self, structure_list: List[Structure]) -> List[Coor return snapping_points def generate_override_structures( - self, grid_size_in_vacuum: float, structure_list: List[Structure] - ) -> List[MeshOverrideStructure]: + self, grid_size_in_vacuum: float, structure_list: list[Structure] + ) -> list[MeshOverrideStructure]: """Generate mesh override structures for mesh refinement.""" return self._override_structures_along_axis( grid_size_in_vacuum @@ -1329,22 +1413,80 @@ def _inplane_inside(self, point: ArrayFloat2D) -> bool: ) return self.inside(point_3d[0], point_3d[1], point_3d[2]) - def _corners(self, structure_list: List[Structure]) -> List[CoordinateOptional]: - """Inplane corners in 3D coordinate.""" + def _corners_and_convexity_2d( + self, structure_list: list[Structure], ravel: bool + ) -> list[CoordinateOptional]: + """Raw inplane corners and their convexity.""" if self.corner_finder is None: - return [] + return [], [] # filter structures outside the layer structures_intersect = structure_list if self._is_inplane_bounded: structures_intersect = [s for s in structure_list if self.intersects(s.geometry)] - inplane_points = self.corner_finder.corners( - self.axis, self.center_axis, structures_intersect + inplane_points, convexity = self.corner_finder._corners_and_convexity( + self.axis, self.center_axis, structures_intersect, ravel ) # filter corners outside the inplane bounds - if self._is_inplane_bounded: - inplane_points = [point for point in inplane_points if self._inplane_inside(point)] + if self._is_inplane_bounded and len(inplane_points) > 0: + # flatten temporary list of arrays for faster processing + if not ravel: + split_inds = np.cumsum([len(pts) for pts in inplane_points])[:-1] + inplane_points = np.concatenate(inplane_points) + convexity = np.concatenate(convexity) + inds = [self._inplane_inside(point) for point in inplane_points] + inplane_points = inplane_points[inds] + convexity = convexity[inds] + if not ravel: + inplane_points = np.split(inplane_points, split_inds) + convexity = np.split(convexity, split_inds) + + return inplane_points, convexity + + def _dl_min_from_smallest_feature(self, structure_list: list[Structure]): + """Calculate `dl_min` suggestion based on smallest feature size.""" + + inplane_points, convexity = self._corners_and_convexity_2d( + structure_list=structure_list, ravel=False + ) + + dl_min = inf + + if self.corner_finder is None or self.corner_finder._no_min_dl_override: + return dl_min + + finder = self.corner_finder + + for points, conv in zip(inplane_points, convexity): + conv_nei = np.roll(conv, -1) + lengths = np.linalg.norm(points - np.roll(points, axis=0, shift=-1), axis=-1) + + if finder.convex_resolution is not None: + convex_features = np.logical_and(conv, conv_nei) + if np.any(convex_features): + min_convex_size = np.min(lengths[convex_features]) + dl_min = min(dl_min, min_convex_size / finder.convex_resolution) + + if finder.concave_resolution is not None: + concave_features = np.logical_not(np.logical_or(conv, conv_nei)) + if np.any(concave_features): + min_concave_size = np.min(lengths[concave_features]) + dl_min = min(dl_min, min_concave_size / finder.concave_resolution) + + if finder.mixed_resolution is not None: + mixed_features = np.logical_xor(conv, conv_nei) + if np.any(mixed_features): + min_mixed_size = np.min(lengths[mixed_features]) + dl_min = min(dl_min, min_mixed_size / finder.mixed_resolution) + + return dl_min + + def _corners(self, structure_list: list[Structure]) -> list[CoordinateOptional]: + """Inplane corners in 3D coordinate.""" + inplane_points, _ = self._corners_and_convexity_2d( + structure_list=structure_list, ravel=True + ) # convert 2d points to 3d return [ @@ -1353,7 +1495,7 @@ def _corners(self, structure_list: List[Structure]) -> List[CoordinateOptional]: ] @property - def _snapping_points_along_axis(self) -> List[CoordinateOptional]: + def _snapping_points_along_axis(self) -> list[CoordinateOptional]: """Snapping points for layer bounds.""" if self.bounds_snapping is None: @@ -1378,8 +1520,8 @@ def _snapping_points_along_axis(self) -> List[CoordinateOptional]: ] def _override_structures_inplane( - self, structure_list: List[Structure], grid_size_in_vacuum: float - ) -> List[MeshOverrideStructure]: + self, structure_list: list[Structure], grid_size_in_vacuum: float + ) -> list[MeshOverrideStructure]: """Inplane mesh override structures for refining mesh around corners.""" if self.corner_refinement is None: return [] @@ -1393,7 +1535,7 @@ def _override_structures_inplane( def _override_structures_along_axis( self, grid_size_in_vacuum: float - ) -> List[MeshOverrideStructure]: + ) -> list[MeshOverrideStructure]: """Mesh override structures for refining mesh along layer axis dimension.""" override_structures = [] @@ -1410,6 +1552,7 @@ def _override_structures_along_axis( dl=self._unpop_axis(ax_coord=dl, plane_coord=None), shadow=False, drop_outside_sim=self.refinement_inside_sim_only, + priority=-1, ) ) @@ -1446,6 +1589,448 @@ def _override_structures_along_axis( override_structures += refinement_structures return override_structures + def _find_vertical_intersections( + self, grid_x_coords, grid_y_coords, poly_vertices, boundary + ) -> tuple[list[tuple[int, int]], list[float]]: + """Detect intersection points of single polygon and vertical grid lines.""" + + # indices of cells that contain intersection with grid lines (left edge of a cell) + cells_ij = [] + # relative displacements of intersection from the bottom of the cell along y axis + cells_dy = [] + + # for each polygon vertex find the index of the first grid line on the right + grid_lines_on_right = np.argmax(grid_x_coords[:, None] >= poly_vertices[None, :, 0], axis=0) + grid_lines_on_right[poly_vertices[:, 0] >= grid_x_coords[-1]] = len(grid_x_coords) + # once we know these indices then we can find grid lines intersected by the i-th + # segment of the polygon as + # [grid_lines_on_right[i], grid_lines_on_right[i+1]) for grid_lines_on_right[i] > grid_lines_on_right[i+1] + # or + # [grid_lines_on_right[i+1], grid_lines_on_right[i]) for grid_lines_on_right[i] < grid_lines_on_right[i+1] + + # loop over segments of the polygon and determine in which cells and where exactly they cross grid lines + # v_beg and v_end are the starting and ending points of the segment + # ind_beg and ind_end are starting and ending indices of vertical grid lines that the segment intersects + # as described above + for ind_beg, ind_end, v_beg, v_end in zip( + grid_lines_on_right, + np.roll(grid_lines_on_right, -1), + poly_vertices, + np.roll(poly_vertices, axis=0, shift=-1), + ): + # no intersections + if ind_end == ind_beg: + continue + + # sort vertices in ascending order to make treatmeant unifrom + reverse = False + if ind_beg > ind_end: + reverse = True + ind_beg, ind_end, v_beg, v_end = ind_end, ind_beg, v_end, v_beg + + # x coordinates are simply x coordinates of intersected vertical grid lines + intersections_x = grid_x_coords[ind_beg:ind_end] + + # y coordinates can be found from line equation + intersections_y = v_beg[1] + (v_end[1] - v_beg[1]) / (v_end[0] - v_beg[0]) * ( + intersections_x - v_beg[0] + ) + + # however, some of the vertical lines might be crossed + # outside of computational domain + # so we need to see which ones are actually inside along y axis + inds_inside_grid = np.logical_and( + intersections_y >= grid_y_coords[0], intersections_y <= grid_y_coords[-1] + ) + + intersections_y = intersections_y[inds_inside_grid] + + # find i and j indices of cells which contain these intersections + + # i indices are simply indices of crossed vertical grid lines + cell_is = np.arange(ind_beg, ind_end)[inds_inside_grid] + + # j indices can be computed by finding insertion indices + # of y coordinates of intersection points into array of y coordinates + # of the grid lines that preserve sorting + cell_js = np.searchsorted(grid_y_coords, intersections_y) - 1 + + # find local dy, that is, the distance between the intersection point + # and the bottom edge of the cell + dy = (intersections_y - grid_y_coords[cell_js]) / ( + grid_y_coords[cell_js + 1] - grid_y_coords[cell_js] + ) + + # preserve uniform ordering along perimeter of the polygon + if reverse: + cell_is = cell_is[::-1] + cell_js = cell_js[::-1] + dy = dy[::-1] + + # record info + cells_ij.append(np.transpose([cell_is, cell_js])) + cells_dy.append(dy) + + if len(cells_ij) > 0: + cells_ij = np.concatenate(cells_ij) + cells_dy = np.concatenate(cells_dy) + + # Filter from re-entering subcell features. That is, we discard any consecutive + # intersections if they are crossing the same edge. This happens, for example, + # when a tiny feature pokes through an edge. This helps not to set dl_min + # to a very low value, and take into account only actual gaps and strips. + + # To do that we use the fact that intersection points are recorded and stored + # in the order as they appear along the border of the polygon. + + # first we calculate linearized indices of edges (cells) they cross + linear_index = cells_ij[:, 0] * len(grid_y_coords) + cells_ij[:, 1] + + # then look at the differences with next and previous neighbors + fwd_diff = linear_index - np.roll(linear_index, -1) + bwd_diff = np.roll(fwd_diff, 1) + + # an intersection point is not a part of a "re-entering subcell feature" + # if it doesn't cross the same edges as its neighbors + valid = np.logical_and(fwd_diff != 0, bwd_diff != 0) + + cells_dy = cells_dy[valid] + cells_ij = cells_ij[valid] + + # Now we are duplicating intersection points very close to cell boundaries + # to corresponding adjacent cells. Basically, if we have a line crossing + # very close to a grid node, we consider that it crosses edges on both sides + # from that node. That is, this serves as a tolerance allowance. + # Note that duplicated intersections and their originals will be snapped to + # cell boundaries during quantization later. + close_to_zero = cells_dy < GAP_MESHING_TOL + close_to_one = (1.0 - cells_dy) < GAP_MESHING_TOL + + points_to_duplicate_near_zero = cells_ij[close_to_zero] + points_to_duplicate_near_one = cells_ij[close_to_one] + + # if we go beyond simulation domain boundary, either ignore + # or wrap periodically depending on boundary conditions + cells_ij_zero_side = points_to_duplicate_near_zero - np.array([0, 1]) + cells_zero_side_out = cells_ij_zero_side[:, 1] == -1 + if boundary[0] == "periodic": + cells_ij_zero_side[cells_zero_side_out, 1] = len(grid_y_coords) - 2 + else: + cells_ij_zero_side = cells_ij_zero_side[cells_zero_side_out == 0] + + cells_ij_one_side = points_to_duplicate_near_one + np.array([0, 1]) + cells_one_side_out = cells_ij_one_side[:, 1] == len(grid_y_coords) - 1 + if boundary[1] == "periodic": + cells_ij_one_side[cells_one_side_out, 1] = 0 + else: + cells_ij_one_side = cells_ij_one_side[cells_one_side_out == 0] + + cells_ij = np.concatenate( + [ + cells_ij, + cells_ij_zero_side, + cells_ij_one_side, + ] + ) + cells_dy = np.concatenate( + [ + cells_dy, + np.ones(len(cells_ij_zero_side)), + np.zeros(len(cells_ij_one_side)), + ] + ) + + return cells_ij, cells_dy + + def _process_poly( + self, grid_x_coords, grid_y_coords, poly_vertices, boundaries + ) -> tuple[list[tuple[int, int]], list[float], list[tuple[int, int]], list[float]]: + """Detect intersection points of single polygon and grid lines.""" + + # find cells that contain intersections of vertical grid lines + # and relative locations of those intersections (along y axis) + v_cells_ij, v_cells_dy = self._find_vertical_intersections( + grid_x_coords, grid_y_coords, poly_vertices, boundaries[1] + ) + + # find cells that contain intersections of horizontal grid lines + # and relative locations of those intersections (along x axis) + # reuse the same command but flip dimensions + h_cells_ij, h_cells_dx = self._find_vertical_intersections( + grid_y_coords, grid_x_coords, np.flip(poly_vertices, axis=1), boundaries[0] + ) + if len(h_cells_ij) > 0: + # flip dimensions back + h_cells_ij = np.roll(h_cells_ij, axis=1, shift=1) + + return v_cells_ij, v_cells_dy, h_cells_ij, h_cells_dx + + def _process_slice( + self, x, y, merged_geos, boundaries + ) -> tuple[list[tuple[int, int]], list[float], list[tuple[int, int]], list[float]]: + """Detect intersection points of geometries boundaries and grid lines.""" + + # cells that contain intersections of vertical grid lines + v_cells_ij = [] + # relative locations of those intersections (along y axis) + v_cells_dy = [] + + # cells that contain intersections of horizontal grid lines + h_cells_ij = [] + # relative locations of those intersections (along x axis) + h_cells_dx = [] + + # for PEC and PMC boundary - treat them as PEC structure + # so that gaps are resolved near boundaries if any + nx = len(x) + ny = len(y) + + if boundaries[0][0] == "pec/pmc": + h_cells_ij.append(np.transpose([np.zeros(ny), np.arange(ny)]).astype(int)) + h_cells_dx.append(np.zeros(ny)) + + if boundaries[0][1] == "pec/pmc": + h_cells_ij.append(np.transpose([(nx - 2) * np.ones(ny), np.arange(ny)]).astype(int)) + h_cells_dx.append(np.ones(ny)) + + if boundaries[1][0] == "pec/pmc": + v_cells_ij.append(np.transpose([np.arange(nx), np.zeros(nx)]).astype(int)) + v_cells_dy.append(np.zeros(nx, dtype=int)) + + if boundaries[1][1] == "pec/pmc": + v_cells_ij.append(np.transpose([np.arange(nx), (ny - 2) * np.ones(nx)]).astype(int)) + v_cells_dy.append(np.ones(nx)) + + # loop over all shapes + for mat, shapes in merged_geos: + if not mat.is_pec: + # note that we expect LossyMetal's converted into PEC in merged_geos + # that is why we are not checking for that separately + continue + polygon_list = ClipOperation.to_polygon_list(shapes) + for poly in polygon_list: + poly = poly.normalize().buffer(0) + + # find intersections of a polygon with grid lines + # specifically: + # 0. cells that contain intersections of vertical grid lines + # 1. relative locations of those intersections along y axis + # 2. cells that contain intersections of horizontal grid lines + # 3. relative locations of those intersections along x axis + data = self._process_poly(x, y, np.array(poly.exterior.coords)[:-1], boundaries) + + if len(data[0]) > 0: + v_cells_ij.append(data[0]) + v_cells_dy.append(data[1]) + + if len(data[2]) > 0: + h_cells_ij.append(data[2]) + h_cells_dx.append(data[3]) + + # in case the polygon has holes + for poly_inner in poly.interiors: + data = self._process_poly(x, y, np.array(poly_inner.coords)[:-1], boundaries) + if len(data[0]) > 0: + v_cells_ij.append(data[0]) + v_cells_dy.append(data[1]) + + if len(data[2]) > 0: + h_cells_ij.append(data[2]) + h_cells_dx.append(data[3]) + + if len(v_cells_ij) > 0: + v_cells_ij = np.concatenate(v_cells_ij) + v_cells_dy = np.concatenate(v_cells_dy) + + if len(h_cells_ij) > 0: + h_cells_ij = np.concatenate(h_cells_ij) + h_cells_dx = np.concatenate(h_cells_dx) + + return v_cells_ij, v_cells_dy, h_cells_ij, h_cells_dx + + def _generate_horizontal_snapping_lines( + self, grid_y_coords, intersected_cells_ij, relative_vert_disp + ) -> tuple[list[CoordinateOptional], float]: + """Convert a list of intersections of vertical grid lines, given as coordinates of cells + and relative vertical displacement inside each cell, into locations of snapping lines that + resolve thin gaps and strips. + """ + min_gap_width = inf + + snapping_lines_y = [] + if len(intersected_cells_ij) > 0: + # quantize intersection locations + relative_vert_disp = np.round(relative_vert_disp / GAP_MESHING_TOL).astype(int) + cell_linear_inds = ( + intersected_cells_ij[:, 0] * len(grid_y_coords) + intersected_cells_ij[:, 1] + ) + cell_linear_inds_and_disps = np.transpose([cell_linear_inds, relative_vert_disp]) + # remove duplicates + cell_linear_inds_and_disps_unique = np.unique(cell_linear_inds_and_disps, axis=0) + + # count intersections of vertical grid lines in each cell + cell_linear_inds_unique, counts = np.unique( + cell_linear_inds_and_disps_unique[:, 0], return_counts=True + ) + # when we count intersections we use linearized 2d index because we really + # need to count intersections in each cell separately + + # but when we need to decide about refinement, due to cartesian nature of grid + # we will need to consider all cells with a given j index at a time + + # so, let's compute j index for each cell in the unique list + cell_linear_inds_unique_j = cell_linear_inds_unique % len(grid_y_coords) + + # loop through all j rows that contain intersections + for ind_j in np.unique(cell_linear_inds_unique_j): + # we need to refine between two grid lines corresponding to index j + # if at least one cell with given j contains > 1 intersections + + # get all intersected cells with given j index + j_selection = cell_linear_inds_unique_j == ind_j + # and number intersections in each of them + counts_j = counts[j_selection] + + # find cell with max intersections + max_count_el = np.argmax(counts_j) + max_count = counts_j[max_count_el] + if max_count > 1: + # get its linear index + target_cell_linear_ind = cell_linear_inds_unique[j_selection][max_count_el] + # look up relative positions of intersections in that cells + target_disps = np.sort( + cell_linear_inds_and_disps_unique[ + cell_linear_inds_and_disps_unique[:, 0] == target_cell_linear_ind, 1 + ] + ) + + # place a snapping line between any two neighboring intersections (in relative units) + relative_snap_lines_pos = ( + 0.5 * (target_disps[1:] + target_disps[:-1]) * GAP_MESHING_TOL + ) + # convert relative positions to absolute ones + snapping_lines_y += [ + grid_y_coords[ind_j] + + rel_pos * (grid_y_coords[ind_j + 1] - grid_y_coords[ind_j]) + for rel_pos in relative_snap_lines_pos + ] + + # compute minimal gap/strip width + min_gap_width_current = ( + np.min(target_disps[1:] - target_disps[:-1]) * GAP_MESHING_TOL + ) + min_gap_width = min( + min_gap_width, + min_gap_width_current * (grid_y_coords[ind_j + 1] - grid_y_coords[ind_j]), + ) + + return snapping_lines_y, min_gap_width + + def _resolve_gaps( + self, structures: list[Structure], grid: Grid, boundaries: tuple, center, size + ) -> tuple[list[CoordinateOptional], float]: + """Detect underresolved gaps and place snapping lines in them. Also return the detected minimal gap width.""" + + # get x and y coordinates of grid lines + _, tan_dims = Box.pop_axis([0, 1, 2], self.axis) + x = grid.boundaries.to_list[tan_dims[0]] + y = grid.boundaries.to_list[tan_dims[1]] + + _, boundaries_tan = Box.pop_axis(boundaries, self.axis) + + # restrict to the size of layer spec + rmin, rmax = self.bounds + _, rmin = Box.pop_axis(rmin, self.axis) + _, rmax = Box.pop_axis(rmax, self.axis) + + new_coords = [] + new_boundaries = [] + for coord, cmin, cmax, bdry in zip([x, y], rmin, rmax, boundaries_tan): + if cmax <= coord[0] or cmin >= coord[-1]: + return [], inf + if cmin < coord[0]: + ind_min = 0 + else: + ind_min = max(0, np.argmax(coord >= cmin) - 1) + + if cmax > coord[-1]: + ind_max = len(coord) - 1 + else: + ind_max = np.argmax(coord >= cmax) + + if ind_min >= ind_max - 1: + return [], inf + + new_coords.append(coord[ind_min : (ind_max + 1)]) + # ignore boundary conditions if we are not touching them + new_boundaries.append( + [ + None if ind_min > 0 else bdry[0], + None if ind_max < len(coord) - 1 else bdry[1], + ] + ) + + x, y = new_coords + + # restrict size of the plane where pec polygons are found in case of periodic boundary conditions + # this is to make sure gaps across periodic boundary conditions are resolved + # (if there is a PEC structure going into periodic boundary, now it will generate a grid line + # intersection next to that boundary and it will be propagated to the other side) + restricted_size_tan = [ + s * (1.0 - dp_eps) if b[0] == "periodic" else inf + for b, s in zip( + new_boundaries, + size, + ) + ] + restricted_size = Box.unpop_axis(size[self.axis], restricted_size_tan, self.axis) + + # get merged pec structures on plane + # note that we expect this function to also convert all LossyMetal's into PEC + plane_slice = CornerFinderSpec._merged_pec_on_plane( + coord=self.center_axis, + normal_axis=self.axis, + structure_list=structures, + center=center, + size=restricted_size, + ) + + # find intersections of pec polygons with grid lines + # specifically: + # 0. cells that contain intersections of vertical grid lines + # 1. relative locations of those intersections along y axis + # 2. cells that contain intersections of horizontal grid lines + # 3. relative locations of those intersections along x axis + v_cells_ij, v_cells_dy, h_cells_ij, h_cells_dx = self._process_slice( + x, y, plane_slice, new_boundaries + ) + + # generate horizontal snapping lines + snapping_lines_y, min_gap_width_along_y = self._generate_horizontal_snapping_lines( + y, v_cells_ij, v_cells_dy + ) + detected_gap_width = min_gap_width_along_y + + # generate vertical snapping lines + if len(h_cells_ij) > 0: # check, otherwise np.roll fails + snapping_lines_x, min_gap_width_along_x = self._generate_horizontal_snapping_lines( + x, np.roll(h_cells_ij, shift=1, axis=1), h_cells_dx + ) + + detected_gap_width = min(detected_gap_width, min_gap_width_along_x) + else: + snapping_lines_x = [] + + # convert snapping lines' coordinates into 3d coordinates + snapping_lines_y_3d = [ + Box.unpop_axis(Y, (None, None), axis=tan_dims[1]) for Y in snapping_lines_y + ] + snapping_lines_x_3d = [ + Box.unpop_axis(X, (None, None), axis=tan_dims[0]) for X in snapping_lines_x + ] + + return snapping_lines_x_3d + snapping_lines_y_3d, detected_gap_width + class GridSpec(Tidy3dBaseModel): """Collective grid specification for all three dimensions. @@ -1506,7 +2091,7 @@ class GridSpec(Tidy3dBaseModel): units=MICROMETER, ) - override_structures: Tuple[annotate_type(StructureType), ...] = pd.Field( + override_structures: tuple[annotate_type(StructureType), ...] = pd.Field( (), title="Grid specification override structures", description="A set of structures that is added on top of the simulation structures in " @@ -1516,7 +2101,7 @@ class GridSpec(Tidy3dBaseModel): "uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", ) - snapping_points: Tuple[CoordinateOptional, ...] = pd.Field( + snapping_points: tuple[CoordinateOptional, ...] = pd.Field( (), title="Grid specification snapping_points", description="A set of points that enforce grid boundaries to pass through them. " @@ -1527,7 +2112,7 @@ class GridSpec(Tidy3dBaseModel): "uses :class:`.AutoGrid` or :class:`.QuasiUniformGrid`.", ) - layer_refinement_specs: Tuple[LayerRefinementSpec, ...] = pd.Field( + layer_refinement_specs: tuple[LayerRefinementSpec, ...] = pd.Field( (), title="Mesh Refinement In Layered Structures", description="Automatic mesh refinement according to layer specifications. The material " @@ -1557,7 +2142,7 @@ def custom_grid_used(self) -> bool: return np.any([isinstance(mesh, (CustomGrid, CustomGridBoundaries)) for mesh in grid_list]) @staticmethod - def wavelength_from_sources(sources: List[SourceType]) -> pd.PositiveFloat: + def wavelength_from_sources(sources: list[SourceType]) -> pd.PositiveFloat: """Define a wavelength based on supplied sources. Called if auto mesh is used and ``self.wavelength is None``.""" @@ -1585,7 +2170,7 @@ def layer_refinement_used(self) -> bool: return len(self.layer_refinement_specs) > 0 @property - def snapping_points_used(self) -> List[bool, bool, bool]: + def snapping_points_used(self) -> list[bool, bool, bool]: """Along each axis, ``True`` if any snapping point is used. However, it is still ``False`` if all snapping points take value ``None`` along the axis. """ @@ -1604,7 +2189,7 @@ def snapping_points_used(self) -> List[bool, bool, bool]: return snapping_used @property - def override_structures_used(self) -> List[bool, bool, bool]: + def override_structures_used(self) -> list[bool, bool, bool]: """Along each axis, ``True`` if any override structure is used. However, it is still ``False`` if only :class:`.MeshOverrideStructure` is supplied, and their ``dl[axis]`` all take the ``None`` value. @@ -1626,8 +2211,8 @@ def override_structures_used(self) -> List[bool, bool, bool]: return override_used def internal_snapping_points( - self, structures: List[Structure], lumped_elements: List[LumpedElementType] - ) -> List[CoordinateOptional]: + self, structures: list[Structure], lumped_elements: list[LumpedElementType] + ) -> list[CoordinateOptional]: """Internal snapping points. So far, internal snapping points are generated by `layer_refinement_specs` and lumped element. @@ -1660,10 +2245,10 @@ def internal_snapping_points( def all_snapping_points( self, - structures: List[Structure], - lumped_elements: List[LumpedElementType], - internal_snapping_points: List[CoordinateOptional] = None, - ) -> List[CoordinateOptional]: + structures: list[Structure], + lumped_elements: list[LumpedElementType], + internal_snapping_points: Optional[list[CoordinateOptional]] = None, + ) -> list[CoordinateOptional]: """Internal and external snapping points. External snapping points take higher priority. So far, internal snapping points are generated by `layer_refinement_specs`. @@ -1689,17 +2274,17 @@ def all_snapping_points( return internal_snapping_points + list(self.snapping_points) @property - def external_override_structures(self) -> List[StructureType]: + def external_override_structures(self) -> list[StructureType]: """External supplied override structure list.""" return [s.to_static() for s in self.override_structures] def internal_override_structures( self, - structures: List[Structure], + structures: list[Structure], wavelength: pd.PositiveFloat, - sim_size: Tuple[float, 3], - lumped_elements: List[LumpedElementType], - ) -> List[StructureType]: + sim_size: tuple[float, 3], + lumped_elements: list[LumpedElementType], + ) -> list[StructureType]: """Internal mesh override structures. So far, internal override structures are generated by `layer_refinement_specs` and lumped element. @@ -1738,14 +2323,15 @@ def internal_override_structures( def all_override_structures( self, - structures: List[Structure], + structures: list[Structure], wavelength: pd.PositiveFloat, - sim_size: Tuple[float, 3], - lumped_elements: List[LumpedElementType], - internal_override_structures: List[MeshOverrideStructure] = None, - ) -> List[StructureType]: - """Internal and external mesh override structures. External override structures take higher priority. - So far, internal override structures all come from `layer_refinement_specs`. + sim_size: tuple[float, 3], + lumped_elements: list[LumpedElementType], + structure_priority_mode: PriorityMode = "equal", + internal_override_structures: Optional[list[MeshOverrideStructure]] = None, + ) -> list[StructureType]: + """Internal and external mesh override structures sorted based on their priority. By default, + the priority of internal override structures is -1, and 0 for external ones. Parameters ---------- @@ -1757,24 +2343,25 @@ def all_override_structures( Simulation domain size. lumped_elements : List[LumpedElementType] List of lumped elements. + structure_priority_mode : PriorityMode + Structure priority setting. internal_override_structures : List[MeshOverrideStructure] If `None`, recomputes internal override structures. Returns ------- List[StructureType] - List of override structures. + List of sorted override structures. """ if internal_override_structures is None: - return ( - self.internal_override_structures(structures, wavelength, sim_size, lumped_elements) - + self.external_override_structures + internal_override_structures = self.internal_override_structures( + structures, wavelength, sim_size, lumped_elements ) + all_structures = internal_override_structures + self.external_override_structures + return Structure._sort_structures(all_structures, structure_priority_mode) - return internal_override_structures + self.external_override_structures - - def _min_vacuum_dl_in_autogrid(self, wavelength: float, sim_size: Tuple[float, 3]) -> float: + def _min_vacuum_dl_in_autogrid(self, wavelength: float, sim_size: tuple[float, 3]) -> float: """Compute grid step size in vacuum for Autogrd. If AutoGrid is applied along more than 1 dimension, return the minimal. """ @@ -1787,9 +2374,9 @@ def _min_vacuum_dl_in_autogrid(self, wavelength: float, sim_size: Tuple[float, 3 def _dl_min( self, wavelength: float, - structure_list: List[StructureType], - sim_size: Tuple[float, 3], - lumped_elements: List[LumpedElementType], + structure_list: list[StructureType], + sim_size: tuple[float, 3], + lumped_elements: list[LumpedElementType], ) -> float: """Lower bound of grid size to be applied to dimensions where AutoGrid with unset `dl_min` (0 or None) is applied. @@ -1817,14 +2404,14 @@ def _dl_min( if self.layer_refinement_used: min_vacuum_dl = self._min_vacuum_dl_in_autogrid(wavelength, sim_size) for layer in self.layer_refinement_specs: - min_dl = min(min_dl, layer.suggested_dl_min(min_vacuum_dl)) + min_dl = min(min_dl, layer.suggested_dl_min(min_vacuum_dl, structures)) # from lumped elements for lumped_element in lumped_elements: for override_structure in lumped_element.to_mesh_overrides(): min_dl = min(min_dl, min(override_structure.dl)) return min_dl * MIN_STEP_BOUND_SCALE - def get_wavelength(self, sources: List[SourceType]) -> float: + def get_wavelength(self, sources: list[SourceType]) -> float: """Get wavelength for automatic mesh generation if needed.""" wavelength = self.wavelength if wavelength is None and self.auto_grid_used: @@ -1834,14 +2421,206 @@ def get_wavelength(self, sources: List[SourceType]) -> float: def make_grid( self, - structures: List[Structure], - symmetry: Tuple[Symmetry, Symmetry, Symmetry], - periodic: Tuple[bool, bool, bool], - sources: List[SourceType], - num_pml_layers: List[Tuple[pd.NonNegativeInt, pd.NonNegativeInt]], - lumped_elements: List[LumpedElementType] = (), - internal_override_structures: List[MeshOverrideStructure] = None, - internal_snapping_points: List[CoordinateOptional] = None, + structures: list[Structure], + symmetry: tuple[Symmetry, Symmetry, Symmetry], + periodic: tuple[bool, bool, bool], + sources: list[SourceType], + num_pml_layers: list[tuple[pd.NonNegativeInt, pd.NonNegativeInt]], + lumped_elements: list[LumpedElementType] = (), + internal_override_structures: Optional[list[MeshOverrideStructure]] = None, + internal_snapping_points: Optional[list[CoordinateOptional]] = None, + boundary_types: tuple[tuple[str, str], tuple[str, str], tuple[str, str]] = [ + [None, None], + [None, None], + [None, None], + ], + structure_priority_mode: PriorityMode = "equal", + ) -> Grid: + """Make the entire simulation grid based on some simulation parameters. + + Parameters + ---------- + structures : List[Structure] + List of structures present in the simulation. The first structure must be the + simulation geometry with the simulation background medium. + symmetry : Tuple[Symmetry, Symmetry, Symmetry] + Reflection symmetry across a plane bisecting the simulation domain + normal to each of the three axes. + periodic: Tuple[bool, bool, bool] + Apply periodic boundary condition or not along each of the dimensions. + Only relevant for autogrids. + sources : List[SourceType] + List of sources. + num_pml_layers : List[Tuple[float, float]] + List containing the number of absorber layers in - and + boundaries. + lumped_elements : List[LumpedElementType] + List of lumped elements. + internal_override_structures : List[MeshOverrideStructure] + If `None`, recomputes internal override structures. + internal_snapping_points : List[CoordinateOptional] + If `None`, recomputes internal snapping points. + boundary_types : Tuple[Tuple[str, str], Tuple[str, str], Tuple[str, str]] = [[None, None], [None, None], [None, None]] + Type of boundary conditions along each dimension: "pec/pmc", "periodic", or + None for any other. This is relevant only for gap meshing. + structure_priority_mode : PriorityMode + Structure priority setting. + + Returns + ------- + Grid: + Entire simulation grid. + """ + + grid, _ = self._make_grid_and_snapping_lines( + structures=structures, + symmetry=symmetry, + periodic=periodic, + sources=sources, + num_pml_layers=num_pml_layers, + lumped_elements=lumped_elements, + internal_override_structures=internal_override_structures, + internal_snapping_points=internal_snapping_points, + structure_priority_mode=structure_priority_mode, + ) + + return grid + + def _make_grid_and_snapping_lines( + self, + structures: list[Structure], + symmetry: tuple[Symmetry, Symmetry, Symmetry], + periodic: tuple[bool, bool, bool], + sources: list[SourceType], + num_pml_layers: list[tuple[pd.NonNegativeInt, pd.NonNegativeInt]], + lumped_elements: list[LumpedElementType] = (), + internal_override_structures: Optional[list[MeshOverrideStructure]] = None, + internal_snapping_points: Optional[list[CoordinateOptional]] = None, + boundary_types: tuple[tuple[str, str], tuple[str, str], tuple[str, str]] = [ + [None, None], + [None, None], + [None, None], + ], + structure_priority_mode: PriorityMode = "equal", + ) -> tuple[Grid, list[CoordinateOptional]]: + """Make the entire simulation grid based on some simulation parameters. + Also return snappiung point resulted from iterative gap meshing. + + Parameters + ---------- + structures : List[Structure] + List of structures present in the simulation. The first structure must be the + simulation geometry with the simulation background medium. + symmetry : Tuple[Symmetry, Symmetry, Symmetry] + Reflection symmetry across a plane bisecting the simulation domain + normal to each of the three axes. + periodic: Tuple[bool, bool, bool] + Apply periodic boundary condition or not along each of the dimensions. + Only relevant for autogrids. + sources : List[SourceType] + List of sources. + num_pml_layers : List[Tuple[float, float]] + List containing the number of absorber layers in - and + boundaries. + lumped_elements : List[LumpedElementType] + List of lumped elements. + internal_override_structures : List[MeshOverrideStructure] + If `None`, recomputes internal override structures. + internal_snapping_points : List[CoordinateOptional] + If `None`, recomputes internal snapping points. + boundary_types : Tuple[Tuple[str, str], Tuple[str, str], Tuple[str, str]] = [[None, None], [None, None], [None, None]] + Type of boundary conditions along each dimension: "pec/pmc", "periodic", or + None for any other. This is relevant only for gap meshing. + structure_priority_mode : PriorityMode + Structure priority setting. + + Returns + ------- + Tuple[Grid, List[CoordinateOptional]]: + Entire simulation grid and snapping points generated during iterative gap meshing. + """ + + old_grid = self._make_grid_one_iteration( + structures=structures, + symmetry=symmetry, + periodic=periodic, + sources=sources, + num_pml_layers=num_pml_layers, + lumped_elements=lumped_elements, + internal_override_structures=internal_override_structures, + internal_snapping_points=internal_snapping_points, + structure_priority_mode=structure_priority_mode, + ) + + sim_geometry = structures[0].geometry + + snapping_lines = [] + if len(self.layer_refinement_specs) > 0: + num_iters = max( + layer_spec.gap_meshing_iters for layer_spec in self.layer_refinement_specs + ) + + min_gap_width = inf + for ind in range(num_iters): + new_snapping_lines = [] + for layer_spec in self.layer_refinement_specs: + if layer_spec.gap_meshing_iters > ind: + one_layer_snapping_lines, gap_width = layer_spec._resolve_gaps( + structures, + old_grid, + boundary_types, + center=sim_geometry.center, + size=sim_geometry.size, + ) + new_snapping_lines = new_snapping_lines + one_layer_snapping_lines + if layer_spec.dl_min_from_gap_width: + min_gap_width = min(min_gap_width, gap_width) + + if len(new_snapping_lines) == 0: + log.info( + "Grid is no longer changing. " + f"Stopping iterative gap meshing after {ind + 1}/{num_iters} iterations." + ) + break + + snapping_lines = snapping_lines + new_snapping_lines + + new_grid = self._make_grid_one_iteration( + structures=structures, + symmetry=symmetry, + periodic=periodic, + sources=sources, + num_pml_layers=num_pml_layers, + lumped_elements=lumped_elements, + internal_override_structures=internal_override_structures, + internal_snapping_points=snapping_lines + internal_snapping_points, + dl_min_from_gaps=0.45 * min_gap_width, + structure_priority_mode=structure_priority_mode, + ) + + same = old_grid == new_grid + + if same: + log.info( + "Grid is no longer changing. " + f"Stopping iterative gap meshing after {ind + 1}/{num_iters} iterations." + ) + break + + old_grid = new_grid + + return old_grid, snapping_lines + + def _make_grid_one_iteration( + self, + structures: list[Structure], + symmetry: tuple[Symmetry, Symmetry, Symmetry], + periodic: tuple[bool, bool, bool], + sources: list[SourceType], + num_pml_layers: list[tuple[pd.NonNegativeInt, pd.NonNegativeInt]], + lumped_elements: list[LumpedElementType] = (), + internal_override_structures: Optional[list[MeshOverrideStructure]] = None, + internal_snapping_points: Optional[list[CoordinateOptional]] = None, + dl_min_from_gaps: pd.PositiveFloat = inf, + structure_priority_mode: PriorityMode = "equal", ) -> Grid: """Make the entire simulation grid based on some simulation parameters. @@ -1853,6 +2632,9 @@ def make_grid( symmetry : Tuple[Symmetry, Symmetry, Symmetry] Reflection symmetry across a plane bisecting the simulation domain normal to each of the three axes. + periodic: Tuple[bool, bool, bool] + Apply periodic boundary condition or not along each of the dimensions. + Only relevant for autogrids. sources : List[SourceType] List of sources. num_pml_layers : List[Tuple[float, float]] @@ -1863,6 +2645,10 @@ def make_grid( If `None`, recomputes internal override structures. internal_snapping_points : List[CoordinateOptional] If `None`, recomputes internal snapping points. + dl_min_from_gaps : pd.PositiveFloat + Minimal grid size computed based on autodetected gaps. + structure_priority_mode : PriorityMode + Structure priority setting. Returns ------- @@ -1908,7 +2694,7 @@ def make_grid( grids_1d = [self.grid_x, self.grid_y, self.grid_z] - if any(s.strip_traced_fields() for s in self.override_structures): + if any(s._strip_traced_fields() for s in self.override_structures): log.warning( "The override structures were detected as having a dependence on the objective " "function parameters. This is not supported by our automatic differentiation " @@ -1925,6 +2711,7 @@ def make_grid( wavelength, sim_size, lumped_elements, + structure_priority_mode, internal_override_structures, ) @@ -1941,6 +2728,7 @@ def make_grid( sim_size, lumped_elements, ) + new_dl_min = min(new_dl_min, dl_min_from_gaps) for ind, grid in enumerate(grids_1d): if isinstance(grid, AutoGrid) and grid._undefined_dl_min: grids_1d[ind] = grid.updated_copy(dl_min=new_dl_min) @@ -1976,12 +2764,12 @@ def auto( wavelength: pd.PositiveFloat = None, min_steps_per_wvl: pd.PositiveFloat = 10.0, max_scale: pd.PositiveFloat = 1.4, - override_structures: List[StructureType] = (), - snapping_points: Tuple[CoordinateOptional, ...] = (), - layer_refinement_specs: List[LayerRefinementSpec] = (), + override_structures: list[StructureType] = (), + snapping_points: tuple[CoordinateOptional, ...] = (), + layer_refinement_specs: list[LayerRefinementSpec] = (), dl_min: pd.NonNegativeFloat = 0.0, min_steps_per_sim_size: pd.PositiveFloat = 10.0, - mesher: MesherType = GradedMesher(), + mesher: MesherType = Undefined, ) -> GridSpec: """Use the same :class:`AutoGrid` along each of the three directions. @@ -2015,6 +2803,8 @@ def auto( GridSpec :class:`GridSpec` with the same automatic nonuniform grid settings in each direction. """ + if mesher is Undefined: + mesher = GradedMesher() grid_1d = AutoGrid( min_steps_per_wvl=min_steps_per_wvl, @@ -2056,9 +2846,9 @@ def quasiuniform( cls, dl: float, max_scale: pd.PositiveFloat = 1.4, - override_structures: List[StructureType] = (), - snapping_points: Tuple[CoordinateOptional, ...] = (), - mesher: MesherType = GradedMesher(), + override_structures: list[StructureType] = (), + snapping_points: tuple[CoordinateOptional, ...] = (), + mesher: MesherType = Undefined, ) -> GridSpec: """Use the same :class:`QuasiUniformGrid` along each of the three directions. @@ -2082,6 +2872,8 @@ def quasiuniform( GridSpec :class:`GridSpec` with the same uniform grid size in each direction. """ + if mesher is Undefined: + mesher = GradedMesher() grid_1d = QuasiUniformGrid(dl=dl, max_scale=max_scale, mesher=mesher) return cls( diff --git a/tidy3d/components/grid/mesher.py b/tidy3d/components/grid/mesher.py index 039e975d0b..fb5c0e39e6 100644 --- a/tidy3d/components/grid/mesher.py +++ b/tidy3d/components/grid/mesher.py @@ -1,10 +1,12 @@ """Collection of functions for automatically generating a nonuniform grid.""" +from __future__ import annotations + import warnings from abc import ABC, abstractmethod from itertools import compress from math import isclose -from typing import Dict, List, Tuple, Union +from typing import Union import numpy as np import pydantic.v1 as pd @@ -13,12 +15,12 @@ from shapely.geometry import box as shapely_box from shapely.strtree import STRtree -from ...constants import C_0, fp_eps -from ...exceptions import SetupError, ValidationError -from ...log import log -from ..base import Tidy3dBaseModel -from ..structure import MeshOverrideStructure, Structure, StructureType -from ..types import ArrayFloat1D, Axis, Bound, CoordinateOptional +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.structure import MeshOverrideStructure, Structure, StructureType +from tidy3d.components.types import ArrayFloat1D, Axis, Bound, CoordinateOptional +from tidy3d.constants import C_0, fp_eps +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log _ROOTS_TOL = 1e-10 @@ -35,12 +37,12 @@ class Mesher(Tidy3dBaseModel, ABC): def parse_structures( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], wavelength: pd.PositiveFloat, min_steps_per_wvl: pd.NonNegativeInt, dl_min: pd.NonNegativeFloat, dl_max: pd.NonNegativeFloat, - ) -> Tuple[ArrayFloat1D, ArrayFloat1D]: + ) -> tuple[ArrayFloat1D, ArrayFloat1D]: """Calculate the positions of all bounding box interfaces along a given axis.""" @abstractmethod @@ -50,8 +52,8 @@ def insert_snapping_points( axis: Axis, interval_coords: ArrayFloat1D, max_dl_list: ArrayFloat1D, - snapping_points: List[CoordinateOptional], - ) -> Tuple[ArrayFloat1D, ArrayFloat1D]: + snapping_points: list[CoordinateOptional], + ) -> tuple[ArrayFloat1D, ArrayFloat1D]: """Insert snapping_points to the intervals.""" @abstractmethod @@ -61,7 +63,7 @@ def make_grid_multiple_intervals( len_interval_list: ArrayFloat1D, max_scale: float, is_periodic: bool, - ) -> List[ArrayFloat1D]: + ) -> list[ArrayFloat1D]: """Create grid steps in multiple connecting intervals.""" @staticmethod @@ -100,8 +102,8 @@ def insert_snapping_points( axis: Axis, interval_coords: ArrayFloat1D, max_dl_list: ArrayFloat1D, - snapping_points: List[CoordinateOptional], - ) -> Tuple[ArrayFloat1D, ArrayFloat1D]: + snapping_points: list[CoordinateOptional], + ) -> tuple[ArrayFloat1D, ArrayFloat1D]: """Insert snapping_points to the intervals. Parameters @@ -158,15 +160,15 @@ def insert_snapping_points( continue # or, if the snapping point is near the first interval boundary, # give priority to the snapping_point and replace - elif d_1 < min_step: + if d_1 < min_step: # Don't replace if the boundary is the simulation boundary - if ind == 0: + if ind == 1: continue interval_coords[ind - 1] = new_coord continue # or, if the snapping point is near the second interval boundary, # give priority to the snapping_point and replace - elif d_2 < min_step: + if d_2 < min_step: # Don't replace if the boundary is the simulation boundary if ind == len(interval_coords) - 1: continue @@ -180,12 +182,12 @@ def insert_snapping_points( def parse_structures( self, axis: Axis, - structures: List[StructureType], + structures: list[StructureType], wavelength: pd.PositiveFloat, min_steps_per_wvl: pd.NonNegativeInt, dl_min: pd.NonNegativeFloat, dl_max: pd.NonNegativeFloat, - ) -> Tuple[ArrayFloat1D, ArrayFloat1D]: + ) -> tuple[ArrayFloat1D, ArrayFloat1D]: """Calculate the positions of all bounding box interfaces along a given axis. In this implementation, in most cases the complexity should be O(len(structures)**2), although the worst-case complexity may approach O(len(structures)**3). @@ -382,14 +384,14 @@ def parse_structures( def insert_bbox( self, - intervals: Dict[str, List], + intervals: dict[str, list], str_ind: int, str_bbox: ArrayFloat1D, - bbox_contained_2d: List[ArrayFloat1D], + bbox_contained_2d: list[ArrayFloat1D], min_step: float, structure_steps: ArrayFloat1D, unshadowed: bool, - ) -> Dict[str, List]: + ) -> dict[str, list]: """Figure out where to place the bounding box coordinates of current structure. For both the left and the right bounds of the structure along the meshing direction, we check if they are not too close to an already existing coordinate, if the @@ -508,8 +510,8 @@ def insert_bbox( @staticmethod def reorder_structures( - structures: List[StructureType], - ) -> Tuple[int, List[StructureType]]: + structures: list[StructureType], + ) -> tuple[int, list[StructureType]]: """Reorder structure list to order as follows: 1). simulation structure `str[0]` remains as the first structure; 2). MeshOverrideStructures with ``shadow=False``; @@ -565,8 +567,8 @@ def reorder_structures( @staticmethod def filter_structures_effective_dl( - structures: List[StructureType], axis: Axis - ) -> List[StructureType]: + structures: list[StructureType], axis: Axis + ) -> list[StructureType]: """For :class:`.MeshOverrideStructure`, we allow ``dl`` along some axis to be ``None`` so that no override occurs along this axis.Here those structures with ``dl[axis]=None`` is filtered. @@ -623,7 +625,7 @@ def structure_step( @staticmethod def structure_steps( - structures: List[StructureType], + structures: list[StructureType], wavelength: float, min_steps_per_wvl: float, dl_min: pd.NonNegativeFloat, @@ -662,7 +664,7 @@ def structure_steps( return np.where(min_steps < dl_min, dl_min, min_steps) @staticmethod - def rotate_structure_bounds(structures: List[StructureType], axis: Axis) -> List[ArrayFloat1D]: + def rotate_structure_bounds(structures: list[StructureType], axis: Axis) -> list[ArrayFloat1D]: """Get structure bounding boxes with a given ``axis`` rotated to z. Parameters @@ -684,12 +686,12 @@ def rotate_structure_bounds(structures: List[StructureType], axis: Axis) -> List bmin, bmax = structure.geometry.bounds bmin_ax, bmin_plane = structure.geometry.pop_axis(bmin, axis=axis) bmax_ax, bmax_plane = structure.geometry.pop_axis(bmax, axis=axis) - bounds = np.array([list(bmin_plane) + [bmin_ax], list(bmax_plane) + [bmax_ax]]) + bounds = np.array([[*list(bmin_plane), bmin_ax], [*list(bmax_plane), bmax_ax]]) struct_bbox.append(bounds) return struct_bbox @staticmethod - def bounds_2d_tree(struct_bbox: List[ArrayFloat1D]): + def bounds_2d_tree(struct_bbox: list[ArrayFloat1D]): """Make a shapely Rtree for the 2D bounding boxes of all structures in the plane perpendicular to the meshing axis.""" @@ -704,7 +706,7 @@ def bounds_2d_tree(struct_bbox: List[ArrayFloat1D]): return stree @staticmethod - def contained_2d(bbox0: ArrayFloat1D, query_bbox: List[ArrayFloat1D]) -> List[ArrayFloat1D]: + def contained_2d(bbox0: ArrayFloat1D, query_bbox: list[ArrayFloat1D]) -> list[ArrayFloat1D]: """Return a list of all bounding boxes among ``query_bbox`` that contain ``bbox0`` in 2D.""" return [ bbox @@ -720,7 +722,7 @@ def contained_2d(bbox0: ArrayFloat1D, query_bbox: List[ArrayFloat1D]) -> List[Ar ] @staticmethod - def contains_3d(bbox0: ArrayFloat1D, query_bbox: List[ArrayFloat1D]) -> List[int]: + def contains_3d(bbox0: ArrayFloat1D, query_bbox: list[ArrayFloat1D]) -> list[int]: """Return a list of all indexes of bounding boxes in the ``query_bbox`` list that ``bbox0`` fully contains.""" return [ @@ -739,7 +741,7 @@ def contains_3d(bbox0: ArrayFloat1D, query_bbox: List[ArrayFloat1D]) -> List[int ] @staticmethod - def is_close(coord: float, interval_coords: List[float], coord_ind: int, atol: float) -> bool: + def is_close(coord: float, interval_coords: list[float], coord_ind: int, atol: float) -> bool: """Check if a given ``coord`` is within ``atol`` of an interval coordinate at a given interval index. If the index is out of bounds, return ``False``.""" return ( @@ -749,7 +751,7 @@ def is_close(coord: float, interval_coords: List[float], coord_ind: int, atol: f ) @staticmethod - def is_contained(normal_pos: float, contained_2d: List[ArrayFloat1D]) -> bool: + def is_contained(normal_pos: float, contained_2d: list[ArrayFloat1D]) -> bool: """Check if a given ``normal_pos`` along the meshing direction is contained inside any of the bounding boxes that are in the ``contained_2d`` list. """ @@ -759,8 +761,8 @@ def is_contained(normal_pos: float, contained_2d: List[ArrayFloat1D]) -> bool: @staticmethod def filter_min_step( - interval_coords: List[float], max_steps: List[float] - ) -> Tuple[List[float], List[float]]: + interval_coords: list[float], max_steps: list[float] + ) -> tuple[list[float], list[float]]: """Filter intervals that are smaller than the absolute smallest of the ``max_steps``.""" # Re-compute minimum step in case some high-index structures were completely covered @@ -784,7 +786,7 @@ def make_grid_multiple_intervals( len_interval_list: ArrayFloat1D, max_scale: float, is_periodic: bool, - ) -> List[ArrayFloat1D]: + ) -> list[ArrayFloat1D]: """Create grid steps in multiple connecting intervals of length specified by ``len_interval_list``. The maximal allowed step size in each interval is given by ``max_dl_list``. The maximum ratio between neighboring steps is bounded by ``max_scale``. @@ -880,7 +882,7 @@ def grid_multiple_interval_analy_refinement( len_interval_list: ArrayFloat1D, max_scale: float, is_periodic: bool, - ) -> Tuple[ArrayFloat1D, ArrayFloat1D]: + ) -> tuple[ArrayFloat1D, ArrayFloat1D]: """Analytical refinement for multiple intervals. "analytical" meaning we allow non-integar step sizes, so that we don't consider snapping here. diff --git a/tidy3d/components/lumped_element.py b/tidy3d/components/lumped_element.py index 8d565f6ebe..70cd6559f1 100644 --- a/tidy3d/components/lumped_element.py +++ b/tidy3d/components/lumped_element.py @@ -9,23 +9,15 @@ import numpy as np import pydantic.v1 as pd +from tidy3d.components.grid.grid import Grid +from tidy3d.components.medium import PEC2D, Debye, Drude, Lorentz, Medium, Medium2D, PoleResidue +from tidy3d.components.monitor import FieldMonitor +from tidy3d.components.structure import MeshOverrideStructure, Structure +from tidy3d.components.validators import assert_line_or_plane, assert_plane, validate_name_str +from tidy3d.constants import EPSILON_0, FARAD, HENRY, MICROMETER, OHM, fp_eps +from tidy3d.exceptions import ValidationError from tidy3d.log import log -from ..components.grid.grid import Grid -from ..components.medium import ( - PEC2D, - Debye, - Drude, - Lorentz, - Medium, - Medium2D, - PoleResidue, -) -from ..components.monitor import FieldMonitor -from ..components.structure import MeshOverrideStructure, Structure -from ..components.validators import assert_line_or_plane, assert_plane, validate_name_str -from ..constants import EPSILON_0, FARAD, HENRY, MICROMETER, OHM, fp_eps -from ..exceptions import ValidationError from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing from .geometry.base import Box, ClipOperation, Geometry, GeometryGroup from .geometry.primitives import Cylinder @@ -160,8 +152,7 @@ def _voltage_axis_2d(self) -> Axis2D: """Returns the voltage axis using the in-plane dimensions used by :class:`.Medium2D`.""" if self.normal_axis > self.voltage_axis: return self.voltage_axis - else: - return self.voltage_axis - 1 + return self.voltage_axis - 1 @cached_property def _snapping_spec(self) -> SnappingSpec: @@ -203,6 +194,7 @@ def to_mesh_overrides(self) -> list[MeshOverrideStructure]: geometry=Box(center=self.center, size=override_size), dl=(dl, dl, dl), shadow=False, + priority=-1, ) ] @@ -408,6 +400,7 @@ def to_mesh_overrides(self) -> list[MeshOverrideStructure]: geometry=Box(center=self.center, size=override_size), dl=override_dl, shadow=False, + priority=-1, ) ] @@ -748,19 +741,18 @@ def _series_network_to_equivalent_medium( tau = 2 * np.pi * R * C med = Debye(eps_inf=1.0, coeffs=[(delta_eps, tau)]) return med.pole_residue - elif R and L: + if R and L: # RL series fi = np.sqrt(admittance_scaling_factor / (EPSILON_0 * (2 * np.pi) ** 2 * L)) di = R / (2 * np.pi * L) med = Drude(eps_inf=1.0, coeffs=[(fi, di)]) return med.pole_residue - else: - # LC series - delta_eps = admittance_scaling_factor * C / EPSILON_0 - di = 0 - fi = np.sqrt(1 / ((2 * np.pi) ** 2 * L * C)) - med = Lorentz(eps_inf=1.0, coeffs=[(delta_eps, fi, di)]) - return med + # LC series + delta_eps = admittance_scaling_factor * C / EPSILON_0 + di = 0 + fi = np.sqrt(1 / ((2 * np.pi) ** 2 * L * C)) + med = Lorentz(eps_inf=1.0, coeffs=[(delta_eps, fi, di)]) + return med @staticmethod def _parallel_network_to_equivalent_medium( @@ -1165,7 +1157,7 @@ def estimate_parasitic_elements(self, grid: Grid) -> tuple[float, float]: else: C = capacitance_rectangular_sheets(width_eff, l_eff, d_sep) return (L, C) - elif connections[0] or connections[1]: + if connections[0] or connections[1]: # Possible to only have a single connection, where the capacitance will be 0 # but there will be a contribution to inductance from the single connection L = inductance_straight_rectangular_wire(common_size, v_axis) diff --git a/tidy3d/components/material/multi_physics.py b/tidy3d/components/material/multi_physics.py index ea60652536..3d675aeb7d 100644 --- a/tidy3d/components/material/multi_physics.py +++ b/tidy3d/components/material/multi_physics.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Optional import pydantic.v1 as pd @@ -139,11 +141,29 @@ def __getattr__(self, name: str): return None DELEGATED_ATTRIBUTES = { - "is_pec": self.optical, + "is_pmc": self.optical, "_eps_plot": self.optical, "viz_spec": self.optical, + "eps_diagonal_numerical": self.optical, + "eps_complex_to_nk": self.optical, + "nonlinear_spec": self.optical, + "is_pec": self.optical, + "is_time_modulated": self.optical, + "is_nonlinear": self.optical, + "is_fully_anisotropic": self.optical, + "is_custom": self.optical, + "is_isotropic": self.optical, + "is_spatially_uniform": self.optical, + "_incompatible_material_types": self.optical, + "frequency_range": self.optical, + "eps_model": self.optical, } + if name == "_has_incompatibilities": + return (self.optical and self.optical._has_incompatibilities) or ( + self.charge and self.charge._has_incompatibilities + ) + if name in DELEGATED_ATTRIBUTES: sub = DELEGATED_ATTRIBUTES[name] if sub is None: @@ -165,5 +185,4 @@ def heat_spec(self): if self.optical is not None: return self.optical.heat_spec - else: - return None + return None diff --git a/tidy3d/components/material/solver_types.py b/tidy3d/components/material/solver_types.py index 6cee7e745e..f597276aa1 100644 --- a/tidy3d/components/material/solver_types.py +++ b/tidy3d/components/material/solver_types.py @@ -2,6 +2,8 @@ Note in the future we might want to implement interpolation models here. """ +from __future__ import annotations + from typing import Union from tidy3d.components.material.tcad.charge import ( diff --git a/tidy3d/components/material/tcad/charge.py b/tidy3d/components/material/tcad/charge.py index 406a862d9d..707e0ebd64 100644 --- a/tidy3d/components/material/tcad/charge.py +++ b/tidy3d/components/material/tcad/charge.py @@ -2,8 +2,6 @@ from __future__ import annotations -from typing import Tuple - import pydantic.v1 as pd from tidy3d.components.data.data_array import SpatialDataArray @@ -289,7 +287,7 @@ class SemiconductorMedium(AbstractChargeMedium): description="Mobility model for holes", ) - R: Tuple[RecombinationModelType, ...] = pd.Field( + R: tuple[RecombinationModelType, ...] = pd.Field( [], title="Generation-Recombination models", description="Array containing the R models to be applied to the material.", @@ -301,14 +299,14 @@ class SemiconductorMedium(AbstractChargeMedium): description="Bandgap narrowing model.", ) - N_a: Union[pd.NonNegativeFloat, SpatialDataArray, Tuple[DopingBoxType, ...]] = pd.Field( + N_a: Union[pd.NonNegativeFloat, SpatialDataArray, tuple[DopingBoxType, ...]] = pd.Field( 0, title="Doping: Acceptor concentration", description="Units of 1/cm^3", units="1/cm^3", ) - N_d: Union[pd.NonNegativeFloat, SpatialDataArray, Tuple[DopingBoxType, ...]] = pd.Field( + N_d: Union[pd.NonNegativeFloat, SpatialDataArray, tuple[DopingBoxType, ...]] = pd.Field( 0, title="Doping: Donor concentration", description="Units of 1/cm^3", diff --git a/tidy3d/components/material/tcad/heat.py b/tidy3d/components/material/tcad/heat.py index fc36ed29c3..a33925f210 100644 --- a/tidy3d/components/material/tcad/heat.py +++ b/tidy3d/components/material/tcad/heat.py @@ -9,6 +9,7 @@ from tidy3d.components.base import Tidy3dBaseModel from tidy3d.constants import ( + DENSITY, SPECIFIC_HEAT_CAPACITY, THERMAL_CONDUCTIVITY, ) @@ -30,17 +31,15 @@ def heat(self): @property def charge(self): - return ValueError(f"A `charge` medium does not exist in this Medium definition: {self}") + raise ValueError(f"A `charge` medium does not exist in this Medium definition: {self}") @property def electrical(self): - return ValueError( - f"An `electrical` medium does not exist in this Medium definition: {self}" - ) + raise ValueError(f"An `electrical` medium does not exist in this Medium definition: {self}") @property def optical(self): - return ValueError(f"An `optical` medium does not exist in this Medium definition: {self}") + raise ValueError(f"An `optical` medium does not exist in this Medium definition: {self}") class FluidMedium(AbstractHeatMedium): @@ -69,8 +68,9 @@ class SolidMedium(AbstractHeatMedium): """ capacity: pd.PositiveFloat = pd.Field( + None, title="Heat capacity", - description=f"Volumetric heat capacity in unit of {SPECIFIC_HEAT_CAPACITY}.", + description=f"Specific heat capacity in unit of {SPECIFIC_HEAT_CAPACITY}.", units=SPECIFIC_HEAT_CAPACITY, ) @@ -80,6 +80,32 @@ class SolidMedium(AbstractHeatMedium): units=THERMAL_CONDUCTIVITY, ) + density: pd.PositiveFloat = pd.Field( + None, + title="Density", + description=f"Mass density of material in units of {DENSITY}.", + units=DENSITY, + ) + + def from_si_units( + conductivity: pd.PositiveFloat, + capacity: pd.PositiveFloat = None, + density: pd.PositiveFloat = None, + ): + """Create a SolidMedium using SI units""" + new_conductivity = conductivity * 1e-6 # Convert from W/(m*K) to W/(um*K) + new_capacity = capacity + new_density = density + + if density is not None: + new_density = density * 1e-18 + + return SolidMedium( + capacity=new_capacity, + conductivity=new_conductivity, + density=new_density, + ) + class SolidSpec(SolidMedium): """Solid medium class for backwards compatibility""" diff --git a/tidy3d/components/material/types.py b/tidy3d/components/material/types.py index cc7150e7f2..3ea694c581 100644 --- a/tidy3d/components/material/types.py +++ b/tidy3d/components/material/types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Union from .multi_physics import MultiPhysicsMedium diff --git a/tidy3d/components/medium.py b/tidy3d/components/medium.py index 1383ce93bf..e186981e72 100644 --- a/tidy3d/components/medium.py +++ b/tidy3d/components/medium.py @@ -3,12 +3,10 @@ from __future__ import annotations import functools -import warnings from abc import ABC, abstractmethod from math import isclose -from typing import Callable, Dict, List, Optional, Tuple, Union +from typing import Callable, Optional, Union -import autograd as ag import autograd.numpy as np # TODO: it's hard to figure out which functions need this, for now all get it @@ -16,11 +14,9 @@ import pydantic.v1 as pd import xarray as xr from numpy.typing import NDArray -from scipy import signal from tidy3d.components.material.tcad.heat import ThermalSpecType - -from ..constants import ( +from tidy3d.constants import ( C_0, CONDUCTIVITY, EPSILON_0, @@ -37,8 +33,9 @@ fp_eps, pec_val, ) -from ..exceptions import SetupError, ValidationError -from ..log import log +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .autograd.derivative_utils import DerivativeInfo, integrate_within_bounds from .autograd.types import AutogradFieldMap, TracedFloat, TracedPoleAndResidue, TracedPositiveFloat from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing @@ -132,7 +129,19 @@ def _eps_model(self, frequency: float) -> complex: # don't warn for evaluating infinite frequency if is_inf_scalar: return eps_model(self, frequency) - if np.any(frequency < fmin * (1 - fp_eps)) or np.any(frequency > fmax * (1 + fp_eps)): + + outside_lower = np.zeros_like(frequency, dtype=bool) + outside_upper = np.zeros_like(frequency, dtype=bool) + + if fmin > 0: + outside_lower = frequency / fmin < 1 - fp_eps + elif fmin == 0: + outside_lower = frequency < 0 + + if fmax > 0: + outside_upper = frequency / fmax > 1 + fp_eps + + if np.any(outside_lower | outside_upper): log.warning( "frequency passed to 'Medium.eps_model()'" f"is outside of 'Medium.frequency_range' = {self.frequency_range}", @@ -170,19 +179,17 @@ def _validate_medium_type(self, medium: AbstractMedium): def _validate_medium(self, medium: AbstractMedium): """Any additional validation that depends on the medium""" - pass - def _validate_medium_freqs(self, medium: AbstractMedium, freqs: List[pd.PositiveFloat]) -> None: + def _validate_medium_freqs(self, medium: AbstractMedium, freqs: list[pd.PositiveFloat]) -> None: """Any additional validation that depends on the central frequencies of the sources.""" - pass def _hardcode_medium_freqs( - self, medium: AbstractMedium, freqs: List[pd.PositiveFloat] + self, medium: AbstractMedium, freqs: list[pd.PositiveFloat] ) -> NonlinearSpec: """Update the nonlinear model to hardcode information on medium and freqs.""" return self - def _get_freq0(self, freq0, freqs: List[pd.PositiveFloat]) -> float: + def _get_freq0(self, freq0, freqs: list[pd.PositiveFloat]) -> float: """Get a single value for freq0.""" # freq0 is not specified; need to calculate it @@ -219,7 +226,7 @@ def _get_n0( self, n0: complex, medium: AbstractMedium, - freqs: List[pd.PositiveFloat], + freqs: list[pd.PositiveFloat], ) -> complex: """Get a single value for n0.""" if freqs is None: @@ -265,7 +272,7 @@ def complex_fields(self) -> bool: return False @property - def aux_fields(self) -> List[str]: + def aux_fields(self) -> list[str]: """List of available aux fields in this model.""" return [] @@ -468,7 +475,7 @@ def _validate_beta_real(cls, val, values): ) return val - def _validate_medium_freqs(self, medium: AbstractMedium, freqs: List[pd.PositiveFloat]) -> None: + def _validate_medium_freqs(self, medium: AbstractMedium, freqs: list[pd.PositiveFloat]) -> None: """Any validation that depends on knowing the central frequencies of the sources. This includes passivity checking, if necessary.""" n0 = self._get_n0(self.n0, medium, freqs) @@ -487,7 +494,7 @@ def _validate_medium_freqs(self, medium: AbstractMedium, freqs: List[pd.Positive ) def _hardcode_medium_freqs( - self, medium: AbstractMedium, freqs: List[pd.PositiveFloat] + self, medium: AbstractMedium, freqs: list[pd.PositiveFloat] ) -> TwoPhotonAbsorption: """Update the nonlinear model to hardcode information on medium and freqs.""" n0 = self._get_n0(n0=self.n0, medium=medium, freqs=freqs) @@ -506,7 +513,7 @@ def complex_fields(self) -> bool: return self.use_complex_fields @property - def aux_fields(self) -> List[str]: + def aux_fields(self) -> list[str]: """List of available aux fields in this model.""" if self.tau == 0: return [] @@ -602,7 +609,7 @@ def _validate_n2_real(cls, val, values): ) return val - def _validate_medium_freqs(self, medium: AbstractMedium, freqs: List[pd.PositiveFloat]) -> None: + def _validate_medium_freqs(self, medium: AbstractMedium, freqs: list[pd.PositiveFloat]) -> None: """Any validation that depends on knowing the central frequencies of the sources. This includes passivity checking, if necessary.""" n0 = self._get_n0(self.n0, medium, freqs) @@ -627,7 +634,7 @@ def _validate_medium(self, medium: AbstractMedium): self._validate_medium_freqs(medium, []) def _hardcode_medium_freqs( - self, medium: AbstractMedium, freqs: List[pd.PositiveFloat] + self, medium: AbstractMedium, freqs: list[pd.PositiveFloat] ) -> KerrNonlinearity: """Update the nonlinear model to hardcode information on medium and freqs.""" n0 = self._get_n0(n0=self.n0, medium=medium, freqs=freqs) @@ -657,7 +664,7 @@ class NonlinearSpec(ABC, Tidy3dBaseModel): >>> medium = Medium(permittivity=2, nonlinear_spec=nonlinear_spec) """ - models: Tuple[NonlinearModelType, ...] = pd.Field( + models: tuple[NonlinearModelType, ...] = pd.Field( (), title="Nonlinear models", description="The nonlinear models present in this nonlinear spec. " @@ -720,7 +727,7 @@ def _validate_num_iters(cls, val, values): return val def _hardcode_medium_freqs( - self, medium: AbstractMedium, freqs: List[pd.PositiveFloat] + self, medium: AbstractMedium, freqs: list[pd.PositiveFloat] ) -> NonlinearSpec: """Update the nonlinear spec to hardcode information on medium and freqs.""" new_models = [] @@ -730,7 +737,7 @@ def _hardcode_medium_freqs( return self.updated_copy(models=new_models) @property - def aux_fields(self) -> List[str]: + def aux_fields(self) -> list[str]: """List of available aux fields in all present models.""" fields = [] for model in self.models: @@ -779,7 +786,7 @@ class AbstractMedium(ABC, Tidy3dBaseModel): ) @cached_property - def _nonlinear_models(self) -> List: + def _nonlinear_models(self) -> list: """The nonlinear models in the nonlinear_spec.""" if self.nonlinear_spec is None: return [] @@ -818,7 +825,7 @@ def _validate_nonlinear_spec(self): comp.nonlinear_spec is not None for comp in [self.ss, self.tt] ): raise ValidationError( - "Nonlinearities are not currently supported for the components " "of a 2D medium." + "Nonlinearities are not currently supported for the components of a 2D medium." ) if self.nonlinear_spec is None: @@ -849,7 +856,7 @@ def _validate_modulation_spec_post_init(self): comp.modulation_spec is not None for comp in [self.ss, self.tt] ): raise ValidationError( - "Time modulation is not currently supported for the components " "of a 2D medium." + "Time modulation is not currently supported for the components of a 2D medium." ) heat_spec: Optional[ThermalSpecType] = pd.Field( @@ -889,7 +896,7 @@ def _validate_modulation_spec(cls, val, values): nonlinear_spec = values.get("nonlinear_spec") if val is not None and nonlinear_spec is not None: raise ValidationError( - f"For medium class {cls}, 'modulation_spec' of class {type(val)} and " + f"For medium class {cls.__name__}, 'modulation_spec' of class {type(val)} and " f"'nonlinear_spec' of class {type(nonlinear_spec)} are " "not simultaneously supported." ) @@ -923,7 +930,7 @@ def is_fully_anisotropic(self) -> bool: return isinstance(self, FullyAnisotropicMedium) @cached_property - def _incompatible_material_types(self) -> List[str]: + def _incompatible_material_types(self) -> list[str]: """A list of material properties present which may lead to incompatibilities.""" properties = [ self.is_time_modulated, @@ -974,7 +981,7 @@ def eps_model(self, frequency: float) -> complex: Complex-valued relative permittivity evaluated at ``frequency``. """ - def nk_model(self, frequency: float) -> Tuple[float, float]: + def nk_model(self, frequency: float) -> tuple[float, float]: """Real and imaginary parts of the refactive index as a function of frequency. Parameters @@ -990,7 +997,7 @@ def nk_model(self, frequency: float) -> Tuple[float, float]: eps_complex = self.eps_model(frequency=frequency) return self.eps_complex_to_nk(eps_complex) - def loss_tangent_model(self, frequency: float) -> Tuple[float, float]: + def loss_tangent_model(self, frequency: float) -> tuple[float, float]: """Permittivity and loss tangent as a function of frequency. Parameters @@ -1007,7 +1014,7 @@ def loss_tangent_model(self, frequency: float) -> Tuple[float, float]: return self.eps_complex_to_eps_loss_tangent(eps_complex) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor as a function of frequency. Parameters @@ -1025,7 +1032,7 @@ def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: eps = self.eps_model(frequency) return (eps, eps, eps) - def eps_diagonal_numerical(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal_numerical(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor for numerical considerations such as meshing and runtime estimation. @@ -1163,7 +1170,7 @@ def nk_to_eps_complex(n: float, k: float = 0.0) -> complex: return eps_real + 1j * eps_imag @staticmethod - def eps_complex_to_nk(eps_c: complex) -> Tuple[float, float]: + def eps_complex_to_nk(eps_c: complex) -> tuple[float, float]: """Convert complex permittivity to n, k values. Parameters @@ -1181,7 +1188,7 @@ def eps_complex_to_nk(eps_c: complex) -> Tuple[float, float]: return np.real(ref_index), np.imag(ref_index) @staticmethod - def nk_to_eps_sigma(n: float, k: float, freq: float) -> Tuple[float, float]: + def nk_to_eps_sigma(n: float, k: float, freq: float) -> tuple[float, float]: """Convert ``n``, ``k`` at frequency ``freq`` to permittivity and conductivity values. Parameters @@ -1230,7 +1237,7 @@ def eps_sigma_to_eps_complex(eps_real: float, sigma: float, freq: float) -> comp return eps_real + 1j * sigma / omega / EPSILON_0 @staticmethod - def eps_complex_to_eps_sigma(eps_complex: complex, freq: float) -> Tuple[float, float]: + def eps_complex_to_eps_sigma(eps_complex: complex, freq: float) -> tuple[float, float]: """Convert complex permittivity at frequency ``freq`` to permittivity and conductivity values. @@ -1252,7 +1259,7 @@ def eps_complex_to_eps_sigma(eps_complex: complex, freq: float) -> Tuple[float, return eps_real, sigma @staticmethod - def eps_complex_to_eps_loss_tangent(eps_complex: complex) -> Tuple[float, float]: + def eps_complex_to_eps_loss_tangent(eps_complex: complex) -> tuple[float, float]: """Convert complex permittivity to permittivity and loss tangent. Parameters @@ -1355,6 +1362,11 @@ def is_pec(self): """Whether the medium is a PEC.""" return False + @cached_property + def is_pmc(self): + """Whether the medium is a PMC.""" + return False + def sel_inside(self, bounds: Bound) -> AbstractMedium: """Return a new medium that contains the minimal amount data necessary to cover a spatial region defined by ``bounds``. @@ -1379,16 +1391,16 @@ def sel_inside(self, bounds: Bound) -> AbstractMedium: """ Autograd code """ - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" raise NotImplementedError(f"Can't compute derivative for 'Medium': '{type(self)}'.") - def derivative_eps_sigma_volume( + def _derivative_eps_sigma_volume( self, E_der_map: ElectromagneticFieldDataset, bounds: Bound, freqs: NDArray ) -> dict[str, xr.DataArray]: """Get the derivative w.r.t permittivity and conductivity in the volume.""" - vjp_eps_complex = self.derivative_eps_complex_volume( + vjp_eps_complex = self._derivative_eps_complex_volume( E_der_map=E_der_map, bounds=bounds, freqs=freqs ) @@ -1399,9 +1411,9 @@ def derivative_eps_sigma_volume( eps_vjp = np.sum(eps_vjp) sigma_vjp = np.sum(sigma_vjp) - return dict(permittivity=eps_vjp, conductivity=sigma_vjp) + return {"permittivity": eps_vjp, "conductivity": sigma_vjp} - def derivative_eps_complex_volume( + def _derivative_eps_complex_volume( self, E_der_map: ElectromagneticFieldDataset, bounds: Bound, freqs: NDArray ) -> xr.DataArray: """Get the derivative w.r.t complex-valued permittivity in the volume.""" @@ -1422,8 +1434,7 @@ def __repr__(self): """If the medium has a name, use it as the representation. Otherwise, use the default representation.""" if self.name: return self.name - else: - return super().__repr__() + return super().__repr__() class AbstractCustomMedium(AbstractMedium, ABC): @@ -1460,7 +1471,7 @@ def _interp_method(self, comp: Axis) -> InterpMethod: @abstractmethod def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -1494,7 +1505,7 @@ def eps_diagonal_on_grid( self, frequency: float, coords: Coords, - ) -> Tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D]: + ) -> tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D]: """Spatial profile of main diagonal of the complex-valued permittivity at ``frequency`` interpolated at the supplied coordinates. @@ -1564,7 +1575,7 @@ def eps_model(self, frequency: float) -> complex: ) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor at ``frequency``. Spatially, we take max{||eps||}, so that autoMesh generation works appropriately. @@ -1584,8 +1595,10 @@ def _get_real_vals(self, x: np.ndarray) -> np.ndarray: return _get_numpy_array(np.real(x)).ravel() def _eps_bounds( - self, frequency: float = None, eps_component: Optional[PermittivityComponent] = None - ) -> Tuple[float, float]: + self, + frequency: Optional[float] = None, + eps_component: Optional[PermittivityComponent] = None, + ) -> tuple[float, float]: """Returns permittivity bounds for setting the color bounds when plotting. Parameters @@ -1614,7 +1627,7 @@ def _validate_isreal_dataarray(dataarray: CustomSpatialDataType) -> bool: @staticmethod def _validate_isreal_dataarray_tuple( - dataarray_tuple: Tuple[CustomSpatialDataType, ...], + dataarray_tuple: tuple[CustomSpatialDataType, ...], ) -> bool: """Validate that the dataarray is real""" return np.all([AbstractCustomMedium._validate_isreal_dataarray(f) for f in dataarray_tuple]) @@ -1650,7 +1663,7 @@ def _not_loaded(field): if isinstance(field, str) and field in DATA_ARRAY_MAP: return True # attempting to construct an UnstructuredGridDataset from a dict - elif isinstance(field, dict) and field.get("type") in ( + if isinstance(field, dict) and field.get("type") in ( "TriangularGridDataset", "TetrahedralGridDataset", ): @@ -1659,7 +1672,7 @@ def _not_loaded(field): for subfield in [field["points"], field["cells"], field["values"]] ) # attempting to pass an UnstructuredGridDataset with zero points - elif isinstance(field, UnstructuredGridDataset): + if isinstance(field, UnstructuredGridDataset): return any(len(subfield) == 0 for subfield in [field.points, field.cells, field.values]) def _derivative_field_cmp( @@ -1672,6 +1685,8 @@ def _derivative_field_cmp( coords_interp = {key: val for key, val in eps_data.coords.items() if len(val) > 1} dims_sum = {dim for dim in eps_data.coords.keys() if dim not in coords_interp} + eps_coordinate_shape = [len(eps_data.coords[dim]) for dim in eps_data.dims if dim in "xyz"] + # compute sizes along each of the interpolation dimensions sizes_list = [] for _, coords in coords_interp.items(): @@ -1703,7 +1718,7 @@ def _derivative_field_cmp( E_der_dim.interp(**coords_interp, assume_sorted=True).fillna(0.0).sum(dims_sum).sum("f") ) vjp_array = np.array(E_der_dim_interp.values).astype(complex) - vjp_array = vjp_array.reshape(eps_data.shape) + vjp_array = vjp_array.reshape(eps_coordinate_shape) # multiply by volume elements (if possible, being defensive here..) try: @@ -1742,7 +1757,7 @@ def _validate_modulation_spec(cls, val): if val is not None: raise ValidationError( f"A 'modulation_spec' of class {type(val)} is not " - f"currently supported for medium class {cls}." + f"currently supported for medium class {cls.__name__}." ) return val @@ -1769,6 +1784,52 @@ def is_pec(self): PEC = PECMedium(name="PEC") +# PMC keyword +class PMCMedium(AbstractMedium): + """Perfect magnetic conductor class. + + Note + ---- + + To avoid confusion from duplicate PMCs, must import ``tidy3d.PMC`` instance directly. + + + + """ + + @pd.validator("modulation_spec", always=True) + def _validate_modulation_spec(cls, val): + """Check compatibility with modulation_spec.""" + if val is not None: + raise ValidationError( + f"A 'modulation_spec' of class {type(val)} is not " + f"currently supported for medium class {cls.__name__}." + ) + return val + + @ensure_freq_in_range + def eps_model(self, frequency: float) -> complex: + # permittivity of a PMC. + return 1.0 + 0j + + @cached_property + def n_cfl(self): + """This property computes the index of refraction related to CFL condition, so that + the FDTD with this medium is stable when the time step size that doesn't take + material factor into account is multiplied by ``n_cfl``. + """ + return 1.0 + + @cached_property + def is_pmc(self): + """Whether the medium is a PMC.""" + return True + + +# PEC builtin instance +PMC = PMCMedium(name="PMC") + + class Medium(AbstractMedium): """Dispersionless medium. Mediums define the optical properties of the materials within the simulation. @@ -1915,11 +1976,11 @@ def from_nk(cls, n: float, k: float, freq: float, **kwargs): ) return cls(permittivity=eps, conductivity=sigma, **kwargs) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" # get vjps w.r.t. permittivity and conductivity of the bulk - vjps_volume = self.derivative_eps_sigma_volume( + vjps_volume = self._derivative_eps_sigma_volume( E_der_map=derivative_info.E_der_map, bounds=derivative_info.bounds, freqs=np.atleast_1d(derivative_info.frequency), @@ -1934,12 +1995,12 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM return derivative_map - def derivative_eps_sigma_volume( + def _derivative_eps_sigma_volume( self, E_der_map: ElectromagneticFieldDataset, bounds: Bound, freqs: NDArray ) -> dict[str, xr.DataArray]: """Get the derivative w.r.t permittivity and conductivity in the volume.""" - vjp_eps_complex = self.derivative_eps_complex_volume( + vjp_eps_complex = self._derivative_eps_complex_volume( E_der_map=E_der_map, bounds=bounds, freqs=freqs ) @@ -1953,9 +2014,9 @@ def derivative_eps_sigma_volume( eps_vjp = np.sum(eps_vjp) sigma_vjp = np.sum(sigma_vjp) - return dict(permittivity=eps_vjp, conductivity=sigma_vjp) + return {"permittivity": eps_vjp, "conductivity": sigma_vjp} - def derivative_eps_complex_volume( + def _derivative_eps_complex_volume( self, E_der_map: ElectromagneticFieldDataset, bounds: Bound, freqs: NDArray ) -> xr.DataArray: """Get the derivative w.r.t complex-valued permittivity in the volume.""" @@ -2077,7 +2138,7 @@ def is_isotropic(self): def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -2214,8 +2275,8 @@ def _warn_if_none(cls, values): ) fail_load = True if fail_load: - eps_real = SpatialDataArray(np.ones((1, 1, 1)), coords=dict(x=[0], y=[0], z=[0])) - return dict(permittivity=eps_real) + eps_real = SpatialDataArray(np.ones((1, 1, 1)), coords={"x": [0], "y": [0], "z": [0]}) + return {"permittivity": eps_real} return values @pd.root_validator(pre=True) @@ -2505,7 +2566,7 @@ def n_cfl(self): def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. () Parameters @@ -2540,7 +2601,7 @@ def eps_diagonal_on_grid( self, frequency: float, coords: Coords, - ) -> Tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D]: + ) -> tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D]: """Spatial profile of main diagonal of the complex-valued permittivity at ``frequency`` interpolated at the supplied coordinates. @@ -2560,7 +2621,7 @@ def eps_diagonal_on_grid( return self._medium.eps_diagonal_on_grid(frequency, coords) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor at ``frequency``. Spatially, we take max{|eps|}, so that autoMesh generation works appropriately. @@ -2578,7 +2639,7 @@ def eps_model(self, frequency: float) -> complex: def from_eps_raw( cls, eps: Union[ScalarFieldDataArray, CustomSpatialDataType], - freq: float = None, + freq: Optional[float] = None, interp_method: InterpMethod = "nearest", **kwargs, ) -> CustomMedium: @@ -2648,7 +2709,7 @@ def from_nk( cls, n: Union[ScalarFieldDataArray, CustomSpatialDataType], k: Optional[Union[ScalarFieldDataArray, CustomSpatialDataType]] = None, - freq: float = None, + freq: Optional[float] = None, interp_method: InterpMethod = "nearest", **kwargs, ) -> CustomMedium: @@ -2731,7 +2792,7 @@ def from_nk( sigma = SpatialDataArray(sigma.squeeze(dim="f", drop=True)) return cls(permittivity=eps_real, conductivity=sigma, interp_method=interp_method, **kwargs) - def grids(self, bounds: Bound) -> Dict[str, Grid]: + def grids(self, bounds: Bound) -> dict[str, Grid]: """Make a :class:`.Grid` corresponding to the data in each ``eps_ii`` component. The min and max coordinates along each dimension are bounded by ``bounds``.""" @@ -2742,7 +2803,7 @@ def grids(self, bounds: Bound) -> Dict[str, Grid]: def make_grid(scalar_field: Union[ScalarFieldDataArray, SpatialDataArray]) -> Grid: """Make a grid for a single dataset.""" - def make_bound_coords(coords: np.ndarray, pt_min: float, pt_max: float) -> List[float]: + def make_bound_coords(coords: np.ndarray, pt_min: float, pt_max: float) -> list[float]: """Convert user supplied coords into boundary coords to use in :class:`.Grid`.""" # get coordinates of the bondaries halfway between user-supplied data @@ -2753,7 +2814,7 @@ def make_bound_coords(coords: np.ndarray, pt_min: float, pt_max: float) -> List[ coord_bounds[coord_bounds >= pt_max] = pt_max # add the geometry bounds in explicitly - return [pt_min] + coord_bounds.tolist() + [pt_max] + return [pt_min, *coord_bounds.tolist(), pt_max] # grab user supplied data long this dimension coords = {key: np.array(val) for key, val in scalar_field.coords.items()} @@ -2829,7 +2890,7 @@ def _sel_custom_data_inside(self, bounds: Bound): eps_dataset=eps_reduced, ) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute the adjoint derivatives for this object.""" vjps = {} @@ -2871,10 +2932,11 @@ def _derivative_field_cmp( freqs: NDArray, ) -> np.ndarray: """Compute derivative with respect to the ``dim`` components within the custom medium.""" - coords_interp = {key: eps_data.coords[key] for key in "xyz"} coords_interp = {key: val for key, val in coords_interp.items() if len(val) > 1} + eps_coordinate_shape = [len(eps_data.coords[dim]) for dim in eps_data.dims if dim in "xyz"] + E_der_dim_interp = E_der_map[f"E{dim}"].sel(f=freqs) for dim_ in "xyz": @@ -2928,7 +2990,7 @@ def _derivative_field_cmp( "message and some information about your simulation setup and we will investigate. " ) vjp_array = E_der_dim_interp.values - vjp_array = vjp_array.reshape(eps_data.shape) + vjp_array = vjp_array.reshape(eps_coordinate_shape) return vjp_array @@ -3021,7 +3083,7 @@ def _validate_conductivity_modulation(cls, val, values): return _validate_conductivity_modulation @abstractmethod - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model.""" @cached_property @@ -3045,14 +3107,14 @@ def n_cfl(self): return n @staticmethod - def tuple_to_complex(value: Tuple[float, float]) -> complex: + def tuple_to_complex(value: tuple[float, float]) -> complex: """Convert a tuple of real and imaginary parts to complex number.""" val_r, val_i = value return val_r + 1j * val_i @staticmethod - def complex_to_tuple(value: complex) -> Tuple[float, float]: + def complex_to_tuple(value: complex) -> tuple[float, float]: """Convert a complex number to a tuple of real and imaginary parts.""" return (value.real, value.imag) @@ -3122,7 +3184,9 @@ def _warn_if_none(cls, values): if fail_load and eps_inf is None: return {nested_tuple_field: ()} if fail_load: - eps_inf = SpatialDataArray(np.ones((1, 1, 1)), coords=dict(x=[0], y=[0], z=[0])) + eps_inf = SpatialDataArray( + np.ones((1, 1, 1)), coords={"x": [0], "y": [0], "z": [0]} + ) return {"eps_inf": eps_inf, nested_tuple_field: ()} return values @@ -3168,7 +3232,7 @@ class PoleResidue(DispersiveMedium): units=PERMITTIVITY, ) - poles: Tuple[TracedPoleAndResidue, ...] = pd.Field( + poles: tuple[TracedPoleAndResidue, ...] = pd.Field( (), title="Poles", description="Tuple of complex-valued (:math:`a_i, c_i`) poles for the model.", @@ -3188,7 +3252,7 @@ def _causality_validation(cls, val): @staticmethod def _eps_model( - eps_inf: pd.PositiveFloat, poles: Tuple[PoleAndResidue, ...], frequency: float + eps_inf: pd.PositiveFloat, poles: tuple[PoleAndResidue, ...], frequency: float ) -> complex: """Complex-valued permittivity as a function of frequency.""" @@ -3206,15 +3270,15 @@ def eps_model(self, frequency: float) -> complex: """Complex-valued permittivity as a function of frequency.""" return self._eps_model(eps_inf=self.eps_inf, poles=self.poles, frequency=frequency) - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model.""" - return dict( - eps_inf=self.eps_inf, - poles=self.poles, - frequency_range=self.frequency_range, - name=self.name, - ) + return { + "eps_inf": self.eps_inf, + "poles": self.poles, + "frequency_range": self.frequency_range, + "name": self.name, + } def __str__(self): """string representation""" @@ -3268,7 +3332,7 @@ def to_medium(self) -> Medium: @staticmethod def lo_to_eps_model( - poles: Tuple[Tuple[float, float, float, float], ...], + poles: tuple[tuple[float, float, float, float], ...], eps_inf: pd.PositiveFloat, frequency: float, ) -> complex: @@ -3300,7 +3364,7 @@ def lo_to_eps_model( @classmethod def from_lo_to( - cls, poles: Tuple[Tuple[float, float, float, float], ...], eps_inf: pd.PositiveFloat = 1 + cls, poles: tuple[tuple[float, float, float, float], ...], eps_inf: pd.PositiveFloat = 1 ) -> PoleResidue: """Construct a pole residue model from the LO-TO form (longitudinal and transverse optical modes). @@ -3372,7 +3436,7 @@ def from_lo_to( return PoleResidue(eps_inf=eps_inf, poles=list(zip(a_coeffs, c_coeffs))) @staticmethod - def imag_ep_extrema(poles: Tuple[PoleAndResidue, ...]) -> ArrayFloat1D: + def imag_ep_extrema(poles: tuple[PoleAndResidue, ...]) -> ArrayFloat1D: """Extrema of Im[eps] in the same unit as poles. Parameters @@ -3422,50 +3486,52 @@ def loss_upper_bound(self) -> float: ep = ep[~np.isnan(ep)] return max(ep.imag) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: - """Compute adjoint derivatives for each of the ``fields`` given the multiplied E and D.""" - - # compute all derivatives beforehand - dJ_deps = self.derivative_eps_complex_volume( - E_der_map=derivative_info.E_der_map, - bounds=derivative_info.bounds, - freqs=np.atleast_1d(derivative_info.frequency), - ) - - dJ_deps = complex(dJ_deps) - - # TODO: fix for multi-frequency - frequency = derivative_info.frequency - poles_complex = [(complex(a), complex(c)) for a, c in self.poles] - poles_complex = np.stack(poles_complex, axis=0) + @staticmethod + def _get_vjps_from_params( + dJ_deps_complex: Union[complex, np.ndarray], + poles_vals: list[tuple[Union[complex, np.ndarray], Union[complex, np.ndarray]]], + omega: float, + requested_paths: list[tuple], + ) -> AutogradFieldMap: + """ + Static helper to compute VJPs from parameters using the analytical chain rule. + """ + jw = 1j * omega + vjps = {} - # compute gradients of eps_model with respect to eps_inf and poles - grad_eps_model = ag.holomorphic_grad(self._eps_model, argnum=(0, 1)) - with warnings.catch_warnings(): - # ignore warnings about holmorphic grad being passed a non-complex input (poles) - warnings.simplefilter("ignore") - deps_deps_inf, deps_dpoles = grad_eps_model( - complex(self.eps_inf), poles_complex, complex(frequency) - ) + if ("eps_inf",) in requested_paths: + vjps[("eps_inf",)] = np.real(dJ_deps_complex) - # multiply with partial dJ/deps to give full gradients + for i, (a_val, c_val) in enumerate(poles_vals): + if any(path[1] == i for path in requested_paths if path[0] == "poles"): + if ("poles", i, 0) in requested_paths: + deps_da = c_val / (jw + a_val) ** 2 + dJ_da = dJ_deps_complex * deps_da + vjps[("poles", i, 0)] = dJ_da + if ("poles", i, 1) in requested_paths: + deps_dc = -1 / (jw + a_val) + dJ_dc = dJ_deps_complex * deps_dc + vjps[("poles", i, 1)] = dJ_dc - dJ_deps_inf = dJ_deps * deps_deps_inf - dJ_dpoles = [(dJ_deps * a, dJ_deps * c) for a, c in deps_dpoles] + return vjps - # get vjps w.r.t. permittivity and conductivity of the bulk - derivative_map = {} - for field_path in derivative_info.paths: - field_name, *rest = field_path + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + """Compute adjoint derivatives by preparing scalar data and calling the static helper.""" - if field_name == "eps_inf": - derivative_map[field_path] = float(np.real(dJ_deps_inf)) + dJ_deps_complex = self._derivative_eps_complex_volume( + E_der_map=derivative_info.E_der_map, + bounds=derivative_info.bounds, + freqs=np.atleast_1d(derivative_info.frequency), + ) - elif field_name == "poles": - pole_index, a_or_c = rest - derivative_map[field_path] = complex(dJ_dpoles[pole_index][a_or_c]) + poles_vals = [(complex(a), complex(c)) for a, c in self.poles] - return derivative_map + return self._get_vjps_from_params( + dJ_deps_complex=complex(dJ_deps_complex), + poles_vals=poles_vals, + omega=2 * np.pi * derivative_info.frequency, + requested_paths=derivative_info.paths, + ) @classmethod def _real_partial_fraction_decomposition( @@ -3492,6 +3558,7 @@ def _real_partial_fraction_decomposition( ``tuple`` is an array of coefficients representing any direct polynomial term. """ + from scipy import signal if a.ndim != 1 or np.any(np.iscomplex(a)): raise ValidationError( @@ -3634,9 +3701,8 @@ def from_admittance_coeffs( "Transfer function is invalid. Direct polynomial term must be real and positive for " "conversion to an equivalent 'PoleResidue' medium." ) - else: - # A pure capacitance will translate to an increased permittivity at infinite frequency. - eps_inf = eps_inf + k[0] + # A pure capacitance will translate to an increased permittivity at infinite frequency. + eps_inf = eps_inf + k[0] pole_residue_from_transfer = PoleResidue(eps_inf=eps_inf, poles=poles_and_residues) @@ -3721,7 +3787,7 @@ class CustomPoleResidue(CustomDispersiveMedium, PoleResidue): units=PERMITTIVITY, ) - poles: Tuple[Tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( + poles: tuple[tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( pd.Field( (), title="Poles", @@ -3771,7 +3837,7 @@ def is_spatially_uniform(self) -> bool: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -3803,7 +3869,7 @@ def eps_dataarray_freq( eps = PoleResidue.eps_model(self, frequency) return (eps, eps, eps) - def poles_on_grid(self, coords: Coords) -> Tuple[Tuple[ArrayComplex3D, ArrayComplex3D], ...]: + def poles_on_grid(self, coords: Coords) -> tuple[tuple[ArrayComplex3D, ArrayComplex3D], ...]: """Spatial profile of poles interpolated at the supplied coordinates. Parameters @@ -3899,74 +3965,29 @@ def _sel_custom_data_inside(self, bounds: Bound): return self.updated_copy(eps_inf=eps_inf_reduced, poles=poles_reduced) - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: - """Compute adjoint derivatives for each of the ``fields`` given the multiplied E and D.""" + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + """Compute adjoint derivatives by preparing array data and calling the static helper.""" - dJ_deps = 0.0 + dJ_deps_complex = 0.0 for dim in "xyz": - dJ_deps += self._derivative_field_cmp( + dJ_deps_complex += self._derivative_field_cmp( E_der_map=derivative_info.E_der_map, eps_data=self.eps_inf, dim=dim, freqs=np.atleast_1d(derivative_info.frequency), ) - # TODO: fix for multi-frequency - frequency = derivative_info.frequency - - poles_complex = [ + poles_vals = [ (np.array(a.values, dtype=complex), np.array(c.values, dtype=complex)) for a, c in self.poles ] - poles_complex = np.stack(poles_complex, axis=0) - - def eps_model_r( - eps_inf: complex, poles: list[tuple[complex, complex]], frequency: float - ) -> float: - """Real part of ``eps_model`` evaluated on ``self`` fields.""" - return np.real(self._eps_model(eps_inf, poles, frequency)) - - def eps_model_i( - eps_inf: complex, poles: list[tuple[complex, complex]], frequency: float - ) -> float: - """Real part of ``eps_model`` evaluated on ``self`` fields.""" - return np.imag(self._eps_model(eps_inf, poles, frequency)) - - # compute the gradients w.r.t. each real and imaginary parts for eps_inf and poles - grad_eps_model_r = ag.elementwise_grad(eps_model_r, argnum=(0, 1)) - grad_eps_model_i = ag.elementwise_grad(eps_model_i, argnum=(0, 1)) - deps_deps_inf_r, deps_dpoles_r = grad_eps_model_r( - self.eps_inf.values, poles_complex, frequency - ) - deps_deps_inf_i, deps_dpoles_i = grad_eps_model_i( - self.eps_inf.values, poles_complex, frequency - ) - - # multiply with dJ_deps partial derivative to give full gradients - - deps_deps_inf = deps_deps_inf_r + 1j * deps_deps_inf_i - dJ_deps_inf = dJ_deps * deps_deps_inf / 3.0 # mysterious 3 - - dJ_dpoles = [] - for (da_r, dc_r), (da_i, dc_i) in zip(deps_dpoles_r, deps_dpoles_i): - da = da_r + 1j * da_i - dc = dc_r + 1j * dc_i - dJ_da = dJ_deps * da / 2.0 # mysterious 2 - dJ_dc = dJ_deps * dc / 2.0 # mysterious 2 - dJ_dpoles.append((dJ_da, dJ_dc)) - - derivative_map = {} - for field_path in derivative_info.paths: - field_name, *rest = field_path - - if field_name == "eps_inf": - derivative_map[field_path] = np.real(dJ_deps_inf) - elif field_name == "poles": - pole_index, a_or_c = rest - derivative_map[field_path] = dJ_dpoles[pole_index][a_or_c] - - return derivative_map + return PoleResidue._get_vjps_from_params( + dJ_deps_complex=dJ_deps_complex, + poles_vals=poles_vals, + omega=2 * np.pi * derivative_info.frequency, + requested_paths=derivative_info.paths, + ) class Sellmeier(DispersiveMedium): @@ -4007,7 +4028,7 @@ class Sellmeier(DispersiveMedium): * `Modeling dispersive material in FDTD `_ """ - coeffs: Tuple[Tuple[float, pd.PositiveFloat], ...] = pd.Field( + coeffs: tuple[tuple[float, pd.PositiveFloat], ...] = pd.Field( title="Coefficients", description="List of Sellmeier (:math:`B_i, C_i`) coefficients.", units=(None, MICROMETER + "^2"), @@ -4062,7 +4083,7 @@ def eps_model(self, frequency: float) -> complex: n = self._n_model(frequency) return AbstractMedium.nk_to_eps_complex(n) - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model""" poles = [] for B, C in self.coeffs: @@ -4071,7 +4092,12 @@ def _pole_residue_dict(self) -> Dict: a = 1j * beta c = 1j * alpha poles.append((a, c)) - return dict(eps_inf=1, poles=poles, frequency_range=self.frequency_range, name=self.name) + return { + "eps_inf": 1, + "poles": poles, + "frequency_range": self.frequency_range, + "name": self.name, + } @staticmethod def _from_dispersion_to_coeffs(n: float, freq: float, dn_dwvl: float): @@ -4146,7 +4172,7 @@ class CustomSellmeier(CustomDispersiveMedium, Sellmeier): * `Modeling dispersive material in FDTD `_ """ - coeffs: Tuple[Tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( + coeffs: tuple[tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( pd.Field( ..., title="Coefficients", @@ -4200,7 +4226,7 @@ def is_spatially_uniform(self) -> bool: return False return True - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model.""" poles_dict = Sellmeier._pole_residue_dict(self) if len(self.coeffs) > 0: @@ -4209,7 +4235,7 @@ def _pole_residue_dict(self) -> Dict: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -4242,7 +4268,7 @@ def eps_dataarray_freq( # if `eps` is simply a float, convert it to a SpatialDataArray ; this is possible when # `coeffs` is empty. if isinstance(eps, (int, float, complex)): - eps = SpatialDataArray(eps * np.ones((1, 1, 1)), coords=dict(x=[0], y=[0], z=[0])) + eps = SpatialDataArray(eps * np.ones((1, 1, 1)), coords={"x": [0], "y": [0], "z": [0]}) return (eps, eps, eps) @classmethod @@ -4363,7 +4389,7 @@ class Lorentz(DispersiveMedium): units=PERMITTIVITY, ) - coeffs: Tuple[Tuple[float, float, pd.NonNegativeFloat], ...] = pd.Field( + coeffs: tuple[tuple[float, float, pd.NonNegativeFloat], ...] = pd.Field( ..., title="Coefficients", description="List of (:math:`\\Delta\\epsilon_i, f_i, \\delta_i`) values for model.", @@ -4406,7 +4432,7 @@ def eps_model(self, frequency: float) -> complex: eps = eps + (de * f**2) / (f**2 - 2j * frequency * delta - frequency**2) return eps - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model.""" poles = [] @@ -4427,12 +4453,12 @@ def _pole_residue_dict(self) -> Dict: c = 1j * de * w**2 / 2 / r poles.append((a, c)) - return dict( - eps_inf=self.eps_inf, - poles=poles, - frequency_range=self.frequency_range, - name=self.name, - ) + return { + "eps_inf": self.eps_inf, + "poles": poles, + "frequency_range": self.frequency_range, + "name": self.name, + } @staticmethod def _all_larger(coeff_a, coeff_b) -> bool: @@ -4544,8 +4570,8 @@ class CustomLorentz(CustomDispersiveMedium, Lorentz): units=PERMITTIVITY, ) - coeffs: Tuple[ - Tuple[ + coeffs: tuple[ + tuple[ CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated, @@ -4641,7 +4667,7 @@ def is_spatially_uniform(self) -> bool: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -4753,7 +4779,7 @@ class Drude(DispersiveMedium): units=PERMITTIVITY, ) - coeffs: Tuple[Tuple[float, pd.PositiveFloat], ...] = pd.Field( + coeffs: tuple[tuple[float, pd.PositiveFloat], ...] = pd.Field( ..., title="Coefficients", description="List of (:math:`f_i, \\delta_i`) values for model.", @@ -4772,7 +4798,7 @@ def eps_model(self, frequency: float) -> complex: eps = eps - (f**2) / (frequency**2 + 1j * frequency * delta) return eps - def _pole_residue_dict(self) -> Dict: + def _pole_residue_dict(self) -> dict: """Dict representation of Medium as a pole-residue model.""" poles = [] @@ -4792,12 +4818,12 @@ def _pole_residue_dict(self) -> Dict: poles.extend(((a0, c0), (a1, c1))) - return dict( - eps_inf=self.eps_inf, - poles=poles, - frequency_range=self.frequency_range, - name=self.name, - ) + return { + "eps_inf": self.eps_inf, + "poles": poles, + "frequency_range": self.frequency_range, + "name": self.name, + } class CustomDrude(CustomDispersiveMedium, Drude): @@ -4846,7 +4872,7 @@ class CustomDrude(CustomDispersiveMedium, Drude): units=PERMITTIVITY, ) - coeffs: Tuple[Tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( + coeffs: tuple[tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( pd.Field( ..., title="Coefficients", @@ -4900,7 +4926,7 @@ def is_spatially_uniform(self) -> bool: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -5005,7 +5031,7 @@ class Debye(DispersiveMedium): units=PERMITTIVITY, ) - coeffs: Tuple[Tuple[float, pd.PositiveFloat], ...] = pd.Field( + coeffs: tuple[tuple[float, pd.PositiveFloat], ...] = pd.Field( ..., title="Coefficients", description="List of (:math:`\\Delta\\epsilon_i, \\tau_i`) values for model.", @@ -5050,12 +5076,12 @@ def _pole_residue_dict(self): poles.append((a, c)) - return dict( - eps_inf=self.eps_inf, - poles=poles, - frequency_range=self.frequency_range, - name=self.name, - ) + return { + "eps_inf": self.eps_inf, + "poles": poles, + "frequency_range": self.frequency_range, + "name": self.name, + } class CustomDebye(CustomDispersiveMedium, Debye): @@ -5103,7 +5129,7 @@ class CustomDebye(CustomDispersiveMedium, Debye): units=PERMITTIVITY, ) - coeffs: Tuple[Tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( + coeffs: tuple[tuple[CustomSpatialDataTypeAnnotated, CustomSpatialDataTypeAnnotated], ...] = ( pd.Field( ..., title="Coefficients", @@ -5172,7 +5198,7 @@ def is_spatially_uniform(self) -> bool: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -5403,7 +5429,7 @@ class HuraySurfaceRoughness(AbstractSurfaceRoughness): description="Relative area of the matte base compared to a flat surface", ) - coeffs: Tuple[Tuple[pd.PositiveFloat, pd.PositiveFloat], ...] = pd.Field( + coeffs: tuple[tuple[pd.PositiveFloat, pd.PositiveFloat], ...] = pd.Field( ..., title="Coefficients for surface ratio and sphere radius", description="List of (:math:`f_i, r_i`) values for model, where :math:`f_i` is " @@ -5509,6 +5535,14 @@ class LossyMetalMedium(Medium): discriminator=TYPE_TAG_STR, ) + thickness: pd.PositiveFloat = pd.Field( + None, + title="Conductor Thickness", + description="When the thickness of the conductor is not much greater than skin depth, " + "1D transmission line model is applied to compute the surface impedance of the thin conductor.", + units=MICROMETER, + ) + frequency_range: FreqBound = pd.Field( ..., title="Frequency Range", @@ -5541,7 +5575,7 @@ def _positive_conductivity(cls, val): return val @cached_property - def _fitting_result(self) -> Tuple[PoleResidue, float]: + def _fitting_result(self) -> tuple[PoleResidue, float]: """Fitted scaled surface impedance and residue.""" omega_data = self.Hz_to_angular_freq(self.sampling_frequencies) @@ -5595,6 +5629,10 @@ def surface_impedance(self, frequencies: ArrayFloat1D): skin_depths = 1 / np.sqrt(np.pi * frequencies * MU_0 * self.conductivity) correction = self.roughness.roughness_correction_factor(frequencies, skin_depths) + if self.thickness is not None: + k_wave = self.Hz_to_angular_freq(frequencies) / C_0 * (n + 1j * k) + correction /= -np.tanh(1j * k_wave * self.thickness) + return correction * ETA_0 / (n + 1j * k) @cached_property @@ -5615,7 +5653,7 @@ def sampling_frequencies(self) -> ArrayFloat1D: self.fit_param.frequency_sampling_points, ) - def eps_diagonal_numerical(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal_numerical(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor for numerical considerations such as meshing and runtime estimation. @@ -5668,9 +5706,10 @@ def plot( return ax -IsotropicUniformMediumType = Union[ +IsotropicUniformMediumFor2DType = Union[ Medium, LossyMetalMedium, PoleResidue, Sellmeier, Lorentz, Debye, Drude, PECMedium ] +IsotropicUniformMediumType = Union[IsotropicUniformMediumFor2DType, PMCMedium] IsotropicCustomMediumType = Union[ CustomPoleResidue, CustomSellmeier, @@ -5744,7 +5783,7 @@ def _validate_modulation_spec(cls, val): if val is not None: raise ValidationError( f"A 'modulation_spec' of class {type(val)} is not " - f"currently supported for medium class {cls}. " + f"currently supported for medium class {cls.__name__}. " "Please add modulation to each component." ) return val @@ -5759,9 +5798,9 @@ def _ignored_fields(cls, values): return values @cached_property - def components(self) -> Dict[str, Medium]: + def components(self) -> dict[str, Medium]: """Dictionary of diagonal medium components.""" - return dict(xx=self.xx, yy=self.yy, zz=self.zz) + return {"xx": self.xx, "yy": self.yy, "zz": self.zz} @cached_property def is_time_modulated(self) -> bool: @@ -5785,7 +5824,7 @@ def eps_model(self, frequency: float) -> complex: return np.mean(self.eps_diagonal(frequency), axis=0) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor as a function of frequency.""" eps_xx = self.xx.eps_model(frequency) @@ -5836,7 +5875,7 @@ def _eps_plot( if eps_component is None: # return the average of the diag return self.eps_model(frequency).real - elif eps_component in ["xx", "yy", "zz"]: + if eps_component in ["xx", "yy", "zz"]: # return the requested diagonal component comp2indx = {"x": 0, "y": 1, "z": 2} return self.eps_comp( @@ -5844,10 +5883,9 @@ def _eps_plot( col=comp2indx[eps_component[1]], frequency=frequency, ).real - else: - raise ValueError( - f"Plotting component '{eps_component}' of a diagonally-anisotropic permittivity tensor is not supported." - ) + raise ValueError( + f"Plotting component '{eps_component}' of a diagonally-anisotropic permittivity tensor is not supported." + ) @add_ax_if_none def plot(self, freqs: float, ax: Ax = None) -> Ax: @@ -5869,19 +5907,28 @@ def plot(self, freqs: float, ax: Ax = None) -> Ax: return ax @property - def elements(self) -> Dict[str, IsotropicUniformMediumType]: + def elements(self) -> dict[str, IsotropicUniformMediumType]: """The diagonal elements of the medium as a dictionary.""" - return dict(xx=self.xx, yy=self.yy, zz=self.zz) + return {"xx": self.xx, "yy": self.yy, "zz": self.zz} @cached_property def is_pec(self): """Whether the medium is a PEC.""" return any(self.is_comp_pec(i) for i in range(3)) + @cached_property + def is_pmc(self): + """Whether the medium is a PMC.""" + return any(self.is_comp_pmc(i) for i in range(3)) + def is_comp_pec(self, comp: Axis): """Whether the medium is a PEC.""" return isinstance(self.components[["xx", "yy", "zz"][comp]], PECMedium) + def is_comp_pmc(self, comp: Axis): + """Whether the medium is a PMC.""" + return isinstance(self.components[["xx", "yy", "zz"][comp]], PMCMedium) + def sel_inside(self, bounds: Bound): """Return a new medium that contains the minimal amount data necessary to cover a spatial region defined by ``bounds``. @@ -5971,7 +6018,7 @@ def _validate_modulation_spec(cls, val): if val is not None: raise ValidationError( f"A 'modulation_spec' of class {type(val)} is not " - f"currently supported for medium class {cls}." + f"currently supported for medium class {cls.__name__}." ) return val @@ -6086,7 +6133,7 @@ def _to_diagonal(self) -> AnisotropicMedium: @cached_property def eps_sigma_diag( self, - ) -> Tuple[Tuple[float, float, float], Tuple[float, float, float], TensorReal]: + ) -> tuple[tuple[float, float, float], tuple[float, float, float], TensorReal]: """Main components of permittivity and conductivity tensors and their directions.""" perm_diag, vecs = np.linalg.eig(self.permittivity) @@ -6106,7 +6153,7 @@ def eps_model(self, frequency: float) -> complex: return np.mean(eps_diag) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor as a function of frequency.""" perm_diag, cond_diag, _ = self.eps_sigma_diag @@ -6340,7 +6387,7 @@ def _interp_method(self, comp: Axis) -> InterpMethod: def eps_dataarray_freq( self, frequency: float - ) -> Tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: + ) -> tuple[CustomSpatialDataType, CustomSpatialDataType, CustomSpatialDataType]: """Permittivity array at ``frequency``. Parameters @@ -6375,8 +6422,10 @@ def eps_dataarray_freq( ) def _eps_bounds( - self, frequency: float = None, eps_component: Optional[PermittivityComponent] = None - ) -> Tuple[float, float]: + self, + frequency: Optional[float] = None, + eps_component: Optional[PermittivityComponent] = None, + ) -> tuple[float, float]: """Returns permittivity bounds for setting the color bounds when plotting. Parameters @@ -6400,13 +6449,12 @@ def _eps_bounds( eps_dataarray = self.eps_dataarray_freq(frequency) eps = self._get_real_vals(eps_dataarray[comps.index(eps_component)]) return (np.min(eps), np.max(eps)) - elif eps_component is None: + if eps_component is None: # Returns the bounds across all components return super()._eps_bounds(frequency=frequency) - else: - raise ValueError( - f"Plotting component '{eps_component}' of a diagonally-anisotropic permittivity tensor is not supported." - ) + raise ValueError( + f"Plotting component '{eps_component}' of a diagonally-anisotropic permittivity tensor is not supported." + ) def _sel_custom_data_inside(self, bounds: Bound): return self @@ -6814,7 +6862,7 @@ class PerturbationPoleResidue(PoleResidue, AbstractPerturbationMedium): ) poles_perturbation: Optional[ - Tuple[Tuple[Optional[ParameterPerturbation], Optional[ParameterPerturbation]], ...] + tuple[tuple[Optional[ParameterPerturbation], Optional[ParameterPerturbation]], ...] ] = pd.Field( None, title="Perturbations of Poles", @@ -6958,7 +7006,7 @@ def perturbed_copy( eps_inf_field = eps_inf_field + delta_eps if delta_sigma is not None: - poles_field = poles_field + [[zeros, 0.5 * delta_sigma / EPSILON_0]] + poles_field = [*poles_field, [zeros, 0.5 * delta_sigma / EPSILON_0]] else: # sample eps_inf if self.eps_inf_perturbation is not None: @@ -6995,6 +7043,7 @@ def perturbed_copy( Medium, AnisotropicMedium, PECMedium, + PMCMedium, PoleResidue, Sellmeier, Lorentz, @@ -7029,7 +7078,7 @@ class Medium2D(AbstractMedium): """ - ss: IsotropicUniformMediumType = pd.Field( + ss: IsotropicUniformMediumFor2DType = pd.Field( ..., title="SS Component", description="Medium describing the ss-component of the diagonal permittivity tensor. " @@ -7040,7 +7089,7 @@ class Medium2D(AbstractMedium): discriminator=TYPE_TAG_STR, ) - tt: IsotropicUniformMediumType = pd.Field( + tt: IsotropicUniformMediumFor2DType = pd.Field( ..., title="TT Component", description="Medium describing the tt-component of the diagonal permittivity tensor. " @@ -7057,12 +7106,12 @@ def _validate_modulation_spec(cls, val): if val is not None: raise ValidationError( f"A 'modulation_spec' of class {type(val)} is not " - f"currently supported for medium class {cls}." + f"currently supported for medium class {cls.__name__}." ) return val - @skip_if_fields_missing(["ss"]) @pd.validator("tt", always=True) + @skip_if_fields_missing(["ss"]) def _validate_inplane_pec(cls, val, values): """ss/tt components must be both PEC or non-PEC.""" if isinstance(val, PECMedium) != isinstance(values["ss"], PECMedium): @@ -7074,7 +7123,7 @@ def _validate_inplane_pec(cls, val, values): @classmethod def _weighted_avg( - cls, meds: List[IsotropicUniformMediumType], weights: List[float] + cls, meds: list[IsotropicUniformMediumFor2DType], weights: list[float] ) -> Union[PoleResidue, PECMedium]: """Average ``meds`` with weights ``weights``.""" eps_inf = 1 @@ -7097,8 +7146,8 @@ def _weighted_avg( def volumetric_equivalent( self, axis: Axis, - adjacent_media: Tuple[MediumType3D, MediumType3D], - adjacent_dls: Tuple[float, float], + adjacent_media: tuple[MediumType3D, MediumType3D], + adjacent_dls: tuple[float, float], ) -> AnisotropicMedium: """Produces a 3D volumetric equivalent medium. The new medium has thickness equal to the average of the ``dls`` in the ``axis`` direction. @@ -7128,7 +7177,7 @@ def volumetric_equivalent( The 3D material corresponding to this 2D material. """ - def get_component(med: MediumType3D, comp: Axis) -> IsotropicUniformMediumType: + def get_component(med: MediumType3D, comp: Axis) -> IsotropicUniformMediumFor2DType: """Extract the ``comp`` component of ``med``.""" if isinstance(med, AnisotropicMedium): dim = "xyz"[comp] @@ -7302,7 +7351,7 @@ def eps_model(self, frequency: float) -> complex: return np.mean(self.eps_diagonal(frequency=frequency), axis=0) @ensure_freq_in_range - def eps_diagonal(self, frequency: float) -> Tuple[complex, complex]: + def eps_diagonal(self, frequency: float) -> tuple[complex, complex]: """Main diagonal of the complex-valued permittivity tensor as a function of frequency.""" log.warning( "The permittivity of a 'Medium2D' is unphysical. " @@ -7314,7 +7363,7 @@ def eps_diagonal(self, frequency: float) -> Tuple[complex, complex]: eps_tt = self.tt.eps_model(frequency) return (eps_ss, eps_tt) - def eps_diagonal_numerical(self, frequency: float) -> Tuple[complex, complex, complex]: + def eps_diagonal_numerical(self, frequency: float) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor for numerical considerations such as meshing and runtime estimation. @@ -7390,9 +7439,9 @@ def sigma_model(self, freq: float) -> complex: return np.mean([self.ss.sigma_model(freq), self.tt.sigma_model(freq)], axis=0) @property - def elements(self) -> Dict[str, IsotropicUniformMediumType]: + def elements(self) -> dict[str, IsotropicUniformMediumFor2DType]: """The diagonal elements of the 2D medium as a dictionary.""" - return dict(ss=self.ss, tt=self.tt) + return {"ss": self.ss, "tt": self.tt} @cached_property def n_cfl(self): diff --git a/tidy3d/components/microwave/data/monitor_data.py b/tidy3d/components/microwave/data/monitor_data.py index aa4048b862..72a34c0d37 100644 --- a/tidy3d/components/microwave/data/monitor_data.py +++ b/tidy3d/components/microwave/data/monitor_data.py @@ -4,6 +4,8 @@ from __future__ import annotations +from typing import Optional + import pydantic.v1 as pd import xarray as xr @@ -119,7 +121,7 @@ def reflection_efficiency(self) -> FreqDataArray: return reflection_efficiency def partial_gain( - self, pol_basis: PolarizationBasis = "linear", tilt_angle: float = None + self, pol_basis: PolarizationBasis = "linear", tilt_angle: Optional[float] = None ) -> xr.Dataset: """The partial gain figures of merit for antennas. The partial gains are computed in the ``linear`` or ``circular`` polarization bases. If ``tilt_angle`` is not ``None``, @@ -161,7 +163,7 @@ def gain(self) -> FieldProjectionAngleDataArray: return partial_G.Gtheta + partial_G.Gphi def partial_realized_gain( - self, pol_basis: PolarizationBasis = "linear", tilt_angle: float = None + self, pol_basis: PolarizationBasis = "linear", tilt_angle: Optional[float] = None ) -> xr.Dataset: """The partial realized gain figures of merit for antennas. The partial gains are computed in the ``linear`` or ``circular`` polarization bases. If ``tilt_angle`` is not ``None``, diff --git a/tidy3d/components/microwave/formulas/circuit_parameters.py b/tidy3d/components/microwave/formulas/circuit_parameters.py index 9eb7c172b8..4514d6e993 100644 --- a/tidy3d/components/microwave/formulas/circuit_parameters.py +++ b/tidy3d/components/microwave/formulas/circuit_parameters.py @@ -11,11 +11,13 @@ Foreign Technology Division Air Force Systems Command U.S. Air Force, 1971. """ +from __future__ import annotations + import numpy as np -from ....constants import EPSILON_0 -from ...geometry.base import Geometry -from ...types import Axis +from tidy3d.components.geometry.base import Geometry +from tidy3d.components.types import Axis +from tidy3d.constants import EPSILON_0 def inductance_straight_rectangular_wire( diff --git a/tidy3d/components/mode/data/sim_data.py b/tidy3d/components/mode/data/sim_data.py index a01bf78375..aed1efde1a 100644 --- a/tidy3d/components/mode/data/sim_data.py +++ b/tidy3d/components/mode/data/sim_data.py @@ -2,18 +2,15 @@ from __future__ import annotations -from typing import Literal, Tuple +from typing import Literal, Optional import pydantic.v1 as pd -from ...base import cached_property -from ...data.monitor_data import ModeSolverData, PermittivityData -from ...data.sim_data import AbstractYeeGridSimulationData -from ...types import ( - Ax, - PlotScale, -) -from ..simulation import ModeSimulation +from tidy3d.components.base import cached_property +from tidy3d.components.data.monitor_data import ModeSolverData, PermittivityData +from tidy3d.components.data.sim_data import AbstractYeeGridSimulationData +from tidy3d.components.mode.simulation import ModeSimulation +from tidy3d.components.types import Ax, PlotScale ModeSimulationMonitorDataType = PermittivityData @@ -31,7 +28,7 @@ class ModeSimulationData(AbstractYeeGridSimulationData): description=":class:`.ModeSolverData` containing the field and effective index on unexpanded grid.", ) - data: Tuple[ModeSimulationMonitorDataType, ...] = pd.Field( + data: tuple[ModeSimulationMonitorDataType, ...] = pd.Field( (), title="Monitor Data", description="List of monitor data " @@ -50,8 +47,8 @@ def plot_field( scale: PlotScale = "lin", eps_alpha: float = 0.2, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, **sel_kwargs, ) -> Ax: diff --git a/tidy3d/components/mode/derivatives.py b/tidy3d/components/mode/derivatives.py index 4c13ca7835..19f0f4b04f 100644 --- a/tidy3d/components/mode/derivatives.py +++ b/tidy3d/components/mode/derivatives.py @@ -1,13 +1,16 @@ """Finite-difference derivatives and PML absorption operators expressed as sparse matrices.""" +from __future__ import annotations + import numpy as np -import scipy.sparse as sp -from ...constants import EPSILON_0, ETA_0 +from tidy3d.constants import EPSILON_0, ETA_0 def make_dxf(dls, shape, pmc): """Forward derivative in x.""" + import scipy.sparse as sp + Nx, Ny = shape if Nx == 1: return sp.csr_matrix((Ny, Ny)) @@ -21,6 +24,8 @@ def make_dxf(dls, shape, pmc): def make_dxb(dls, shape, pmc): """Backward derivative in x.""" + import scipy.sparse as sp + Nx, Ny = shape if Nx == 1: return sp.csr_matrix((Ny, Ny)) @@ -36,6 +41,8 @@ def make_dxb(dls, shape, pmc): def make_dyf(dls, shape, pmc): """Forward derivative in y.""" + import scipy.sparse as sp + Nx, Ny = shape if Ny == 1: return sp.csr_matrix((Nx, Nx)) @@ -49,6 +56,8 @@ def make_dyf(dls, shape, pmc): def make_dyb(dls, shape, pmc): """Backward derivative in y.""" + import scipy.sparse as sp + Nx, Ny = shape if Ny == 1: return sp.csr_matrix((Nx, Nx)) @@ -80,6 +89,7 @@ def create_s_matrices(omega, shape, npml, dls, eps_tensor, mu_tensor, dmin_pml=( """Makes the 'S-matrices'. When dotted with derivative matrices, they add PML. If dmin_pml is set to False, PML will not be applied on the "bottom" side of the domain.""" + import scipy.sparse as sp # strip out some information needed Nx, Ny = shape diff --git a/tidy3d/components/mode/mode_solver.py b/tidy3d/components/mode/mode_solver.py index 41b32c91cd..6dcc89e27d 100644 --- a/tidy3d/components/mode/mode_solver.py +++ b/tidy3d/components/mode/mode_solver.py @@ -6,41 +6,40 @@ from functools import wraps from math import isclose -from typing import Dict, List, Tuple, Union +from typing import Literal, Optional, Union, get_args import numpy as np import pydantic.v1 as pydantic import xarray as xr -from matplotlib.collections import PatchCollection -from matplotlib.patches import Rectangle - -from ...constants import C_0 -from ...exceptions import SetupError, ValidationError -from ...log import log -from ..base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ..boundary import PML, Absorber, Boundary, BoundarySpec, PECBoundary, StablePML -from ..data.data_array import ( + +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.boundary import PML, Absorber, Boundary, BoundarySpec, PECBoundary, StablePML +from tidy3d.components.data.data_array import ( FreqModeDataArray, ModeIndexDataArray, ScalarModeFieldCylindricalDataArray, ScalarModeFieldDataArray, ) -from ..data.monitor_data import ModeSolverData -from ..data.sim_data import SimulationData -from ..eme.data.sim_data import EMESimulationData -from ..eme.simulation import EMESimulation -from ..geometry.base import Box -from ..grid.grid import Coords, Grid -from ..medium import FullyAnisotropicMedium, LossyMetalMedium -from ..mode_spec import ModeSpec -from ..monitor import ModeMonitor, ModeSolverMonitor -from ..scene import Scene -from ..simulation import Simulation -from ..source.field import ModeSource -from ..source.time import SourceTime -from ..structure import Structure -from ..subpixel_spec import SurfaceImpedance -from ..types import ( +from tidy3d.components.data.monitor_data import ModeSolverData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.eme.data.sim_data import EMESimulationData +from tidy3d.components.eme.simulation import EMESimulation +from tidy3d.components.geometry.base import Box +from tidy3d.components.grid.grid import Coords, Grid +from tidy3d.components.medium import ( + FullyAnisotropicMedium, + IsotropicUniformMediumType, + LossyMetalMedium, +) +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor +from tidy3d.components.scene import Scene +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.field import ModeSource +from tidy3d.components.source.time import SourceTime +from tidy3d.components.structure import Structure +from tidy3d.components.subpixel_spec import SurfaceImpedance +from tidy3d.components.types import ( TYPE_TAG_STR, ArrayComplex3D, ArrayComplex4D, @@ -53,16 +52,18 @@ EMField, EpsSpecType, FreqArray, - Literal, PlotScale, Symmetry, ) -from ..validators import ( +from tidy3d.components.validators import ( validate_freqs_min, validate_freqs_not_empty, - validate_mode_plane_radius, ) -from ..viz import make_ax, plot_params_pml +from tidy3d.components.viz import make_ax, plot_params_pml +from tidy3d.constants import C_0 +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log +from tidy3d.packaging import supports_local_subpixel, tidy3d_extras # Importing the local solver may not work if e.g. scipy is not installed IMPORT_ERROR_MSG = """Could not import local solver, 'ModeSolver' objects can still be constructed @@ -76,7 +77,7 @@ log.warning(IMPORT_ERROR_MSG) LOCAL_SOLVER_IMPORTED = False -FIELD = Tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D] +FIELD = tuple[ArrayComplex3D, ArrayComplex3D, ArrayComplex3D] MODE_MONITOR_NAME = "<<>>" # Warning for field intensity at edges over total field intensity larger than this value @@ -169,7 +170,7 @@ class ModeSolver(Tidy3dBaseModel): "primal grid nodes). Default is ``True``.", ) - fields: Tuple[EMField, ...] = pydantic.Field( + fields: tuple[EMField, ...] = pydantic.Field( ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], title="Field Components", description="Collection of field components to store in the monitor. Note that some " @@ -210,15 +211,46 @@ def plane_in_sim_bounds(cls, val, values): raise SetupError("'ModeSolver.plane' must intersect 'ModeSolver.simulation'.") return val + @pydantic.validator("plane", always=True) + @skip_if_fields_missing(["simulation"]) + def _warn_plane_crosses_symmetry(cls, val, values): + """Warn if the mode plane crosses the symmetry plane of the underlying simulation but + the centers do not match.""" + simulation = values.get("simulation") + bounds = val.bounds + # now check in each dimension whether we cross symmetry plane + for dim in range(3): + if simulation.symmetry[dim] != 0: + crosses_symmetry = ( + bounds[0][dim] < simulation.center[dim] + and bounds[1][dim] > simulation.center[dim] + ) + if crosses_symmetry: + if not isclose(val.center[dim], simulation.center[dim]): + log.warning( + f"The original simulation is symmetric along {'xyz'[dim]} direction. " + "The mode simulation region does cross the symmetry plane but is " + "not symmetric with respect to it. To preserve correct symmetry, " + "the requested simulation region will be expanded by the solver." + ) + return val + def _post_init_validators(self) -> None: - validate_mode_plane_radius( - mode_spec=self.mode_spec, plane=self.plane, msg_prefix="Mode solver" + self._validate_mode_plane_radius( + mode_spec=self.mode_spec, + plane=self.plane, + sim_geom=self.simulation.geometry, ) self._warn_thick_pml(simulation=self.simulation, plane=self.plane, mode_spec=self.mode_spec) + self._validate_rotate_structures() @classmethod def _warn_thick_pml( - cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec, warn_str: str = "'ModeSolver'" + cls, + simulation: Simulation, + plane: Box, + mode_spec: ModeSpec, + msg_prefix: str = "'ModeSolver'", ): """Warn if the pml covers a significant portion of the mode plane.""" coord_0, coord_1 = cls._plane_grid( @@ -232,13 +264,45 @@ def _warn_thick_pml( for i in (0, 1): if 2 * effective_num_pml[i] > (WARN_THICK_PML_PERCENT / 100) * num_cells[i]: log.warning( - f"{warn_str}: " + f"{msg_prefix}: " f"The mode solver pml in tangential axis '{i}' " f"covers more than '{WARN_THICK_PML_PERCENT}%' of the " "mode plane cells. Consider using a larger mode plane " "or smaller 'num_pml'." ) + @staticmethod + def _mode_plane(plane: Box, sim_geom: Box) -> Box: + """Intersect the mode plane with the sim geometry to get the effective + mode plane.""" + mode_plane_bnds = plane.bounds_intersection(plane.bounds, sim_geom.bounds) + return Box.from_bounds(*mode_plane_bnds) + + @classmethod + def _validate_mode_plane_radius(cls, mode_spec: ModeSpec, plane: Box, sim_geom: Box): + """Validate that the radius of a mode spec with a bend is not smaller than half the size of + the plane along the radial direction.""" + + if not mode_spec.bend_radius: + return + + mode_plane = cls._mode_plane(plane=plane, sim_geom=sim_geom) + + # radial axis is the plane axis that is not the bend axis + _, plane_axs = mode_plane.pop_axis([0, 1, 2], mode_plane.size.index(0.0)) + radial_ax = plane_axs[(mode_spec.bend_axis + 1) % 2] + + if np.abs(mode_spec.bend_radius) < mode_plane.size[radial_ax] / 2: + raise ValueError( + "Mode solver bend radius is smaller than half the mode plane size " + "along the radial axis, which can produce wrong results." + ) + + def _validate_rotate_structures(self) -> None: + """Validate that structures can be rotated if angle_rotation is True.""" + if np.abs(self.mode_spec.angle_theta) > 0 and self.mode_spec.angle_rotation: + _ = self._rotate_structures + @cached_property def normal_axis(self) -> Axis: """Axis normal to the mode plane.""" @@ -258,7 +322,7 @@ def normal_axis_2d(self) -> Axis2D: return idx_plane.index(self.normal_axis) @staticmethod - def _solver_symmetry(simulation: Simulation, plane: Box) -> Tuple[Symmetry, Symmetry]: + def _solver_symmetry(simulation: Simulation, plane: Box) -> tuple[Symmetry, Symmetry]: """Get symmetry for solver for propagation along self.normal axis.""" normal_axis = plane.size.index(0.0) mode_symmetry = list(simulation.symmetry) @@ -269,7 +333,7 @@ def _solver_symmetry(simulation: Simulation, plane: Box) -> Tuple[Symmetry, Symm return solver_sym @cached_property - def solver_symmetry(self) -> Tuple[Symmetry, Symmetry]: + def solver_symmetry(self) -> tuple[Symmetry, Symmetry]: """Get symmetry for solver for propagation along self.normal axis.""" return self._solver_symmetry(simulation=self.simulation, plane=self.plane) @@ -317,7 +381,7 @@ def _get_solver_grid( _, plane_inds = Box.pop_axis([0, 1, 2], normal_axis) for dim, sym in enumerate(solver_symmetry): if sym != 0: - span_inds[plane_inds[dim], 0] += np.diff(span_inds[plane_inds[dim]]) // 2 + span_inds[plane_inds[dim], 0] += np.diff(span_inds[plane_inds[dim]])[0] // 2 return simulation._subgrid(span_inds=span_inds) @@ -337,7 +401,7 @@ def _solver_grid(self) -> Grid: ) @cached_property - def _num_cells_freqs_modes(self) -> Tuple[int, int, int]: + def _num_cells_freqs_modes(self) -> tuple[int, int, int]: """Get the number of spatial points, number of freqs, and number of modes requested.""" num_cells = np.prod(self._solver_grid.num_cells) num_modes = self.mode_spec.num_modes @@ -493,7 +557,7 @@ def rotated_mode_solver_data(self) -> ModeSolverData: log.warning( "Mode solver reduced_simulation_copy failed. " "Falling back to non-reduced simulation, which may be slower. " - f"Exception: {str(e)}" + f"Exception: {e!s}" ) # Compute the mode solution by rotating the reference data to the monitor plane @@ -547,7 +611,7 @@ def rotated_structures_copy(self): to the simulation and updates the ModeSpec to disable bend correction and reset angles to normal.""" - rotated_structures = self._rotate_structures() + rotated_structures = self._rotate_structures rotated_simulation = self.simulation.updated_copy(structures=rotated_structures) rotated_mode_spec = self.mode_spec.updated_copy( angle_rotation=False, angle_theta=0, angle_phi=0 @@ -555,7 +619,8 @@ def rotated_structures_copy(self): return self.updated_copy(simulation=rotated_simulation, mode_spec=rotated_mode_spec) - def _rotate_structures(self) -> List[Structure]: + @cached_property + def _rotate_structures(self) -> list[Structure]: """Rotate the structures intersecting with modal plane by angle theta if bend_correction is enabeled for bend simulations.""" @@ -579,28 +644,44 @@ def _rotate_structures(self) -> List[Structure]: translate_coords = [0, 0, 0] translate_coords[idx_u] = mnt_center[idx_u] translate_coords[idx_v] = mnt_center[idx_v] + translate_kwargs = dict(zip("xyz", translate_coords)) + # Rotation arguments + rotate_kwargs = {"angle": theta, "axis": self.bend_axis_3d} - reduced_sim_solver = self.reduced_simulation_copy - rotated_structures = [] - for structure in Scene.intersecting_structures( - self.plane, reduced_sim_solver.simulation.structures - ): - # Rotate and apply translations - geometry = structure.geometry - geometry = ( - geometry.translated( - x=-translate_coords[0], y=-translate_coords[1], z=-translate_coords[2] + structs_in = Scene.intersecting_structures(self.plane, self.simulation.structures) + return self._make_rotated_structures(structs_in, translate_kwargs, rotate_kwargs) + + @staticmethod + def _make_rotated_structures( + structures: list[Structure], translate_kwargs: dict, rotate_kwargs: dict + ): + try: + rotated_structures = [] + for structure in structures: + if not isinstance(structure.medium, get_args(IsotropicUniformMediumType)): + raise NotImplementedError( + "Mode solver plane intersects an unsupported medium. " + "Only uniform isotropic media are supported for the plane rotation." + ) + + # Rotate and apply translations + geometry = structure.geometry + geometry = ( + geometry.translated(**{key: -val for key, val in translate_kwargs.items()}) + .rotated(**rotate_kwargs) + .translated(**translate_kwargs) ) - .rotated(theta, axis=self.bend_axis_3d) - .translated(x=translate_coords[0], y=translate_coords[1], z=translate_coords[2]) - ) - rotated_structures.append(structure.updated_copy(geometry=geometry)) + rotated_structures.append(structure.updated_copy(geometry=geometry)) - return rotated_structures + return rotated_structures + except Exception as e: + raise SetupError( + f"'angle_rotation' set to True but could not rotate structures: {e!s}" + ) from e @cached_property - def rotated_bend_center(self) -> List: + def rotated_bend_center(self) -> list: """Calculate the center at the rotated bend such that the modal plane is normal to the azimuthal direction of the bend.""" rotated_bend_center = list(self.plane.center) @@ -636,7 +717,7 @@ def rotated_bend_center(self) -> List: def _car_2_cyn( self, mode_solver_data: ModeSolverData - ) -> Dict[Union[ScalarModeFieldCylindricalDataArray, ModeIndexDataArray]]: + ) -> dict[Union[ScalarModeFieldCylindricalDataArray, ModeIndexDataArray]]: """Convert cartesian fields to cylindrical fields centered at the rotated bend center.""" @@ -836,7 +917,7 @@ def _car_2_cyn( def _mode_rotation( self, - solver_ref_data_cylindrical: Dict[ + solver_ref_data_cylindrical: dict[ Union[ScalarModeFieldCylindricalDataArray, ModeIndexDataArray] ], solver: ModeSolver, @@ -991,7 +1072,7 @@ def _bend_radius(self): return EFFECTIVE_RADIUS_FACTOR * largest_dim @cached_property - def bend_center(self) -> List: + def bend_center(self) -> list: """Computes the bend center based on plane center, angle_theta and angle_phi.""" _, id_bend_uv = self.plane.pop_axis((0, 1, 2), axis=self.bend_axis_3d) @@ -1042,7 +1123,7 @@ def _data_on_yee_grid(self) -> ModeSolverData: log.warning( "Mode solver reduced_simulation_copy failed. " "Falling back to non-reduced simulation, which may be slower. " - f"Exception: {str(e)}" + f"Exception: {e!s}" ) _, _solver_coords = solver.plane.pop_axis( @@ -1057,10 +1138,10 @@ def _data_on_yee_grid(self) -> ModeSolverData: # start a dictionary storing the data arrays for the ModeSolverData index_data = ModeIndexDataArray( np.stack(n_complex, axis=0), - coords=dict( - f=list(solver.freqs), - mode_index=np.arange(solver.mode_spec.num_modes), - ), + coords={ + "f": list(solver.freqs), + "mode_index": np.arange(solver.mode_spec.num_modes), + }, ) data_dict = {"n_complex": index_data} @@ -1069,13 +1150,13 @@ def _data_on_yee_grid(self) -> ModeSolverData: xyz_coords = solver.grid_snapped[field_name].to_list scalar_field_data = ScalarModeFieldDataArray( np.stack([field_freq[field_name] for field_freq in fields], axis=-2), - coords=dict( - x=xyz_coords[0], - y=xyz_coords[1], - z=xyz_coords[2], - f=list(solver.freqs), - mode_index=np.arange(solver.mode_spec.num_modes), - ), + coords={ + "x": xyz_coords[0], + "y": xyz_coords[1], + "z": xyz_coords[2], + "f": list(solver.freqs), + "mode_index": np.arange(solver.mode_spec.num_modes), + }, ) data_dict[field_name] = scalar_field_data @@ -1129,10 +1210,10 @@ def _data_on_yee_grid_relative(self, basis: ModeSolverData) -> ModeSolverData: # start a dictionary storing the data arrays for the ModeSolverData index_data = ModeIndexDataArray( np.stack(n_complex, axis=0), - coords=dict( - f=list(self.freqs), - mode_index=np.arange(self.mode_spec.num_modes), - ), + coords={ + "f": list(self.freqs), + "mode_index": np.arange(self.mode_spec.num_modes), + }, ) data_dict = {"n_complex": index_data} @@ -1141,13 +1222,13 @@ def _data_on_yee_grid_relative(self, basis: ModeSolverData) -> ModeSolverData: xyz_coords = self.grid_snapped[field_name].to_list scalar_field_data = ScalarModeFieldDataArray( np.stack([field_freq[field_name] for field_freq in fields], axis=-2), - coords=dict( - x=xyz_coords[0], - y=xyz_coords[1], - z=xyz_coords[2], - f=list(self.freqs), - mode_index=np.arange(self.mode_spec.num_modes), - ), + coords={ + "x": xyz_coords[0], + "y": xyz_coords[1], + "z": xyz_coords[2], + "f": list(self.freqs), + "mode_index": np.arange(self.mode_spec.num_modes), + }, ) data_dict[field_name] = scalar_field_data @@ -1176,7 +1257,7 @@ def _data_on_yee_grid_relative(self, basis: ModeSolverData) -> ModeSolverData: return mode_solver_data - def _get_colocation_coordinates(self) -> Dict[str, ArrayFloat1D]: + def _get_colocation_coordinates(self) -> dict[str, ArrayFloat1D]: """Get colocation coordinates in the solver plane. Returns: @@ -1249,7 +1330,8 @@ def _filter_polarization(self, mode_solver_data: ModeSolverData): np.where(np.isnan(te_frac))[0], ) ) - for data in list(mode_solver_data.field_components.values()) + [ + for data in [ + *list(mode_solver_data.field_components.values()), mode_solver_data.n_complex, mode_solver_data.grid_primal_correction, mode_solver_data.grid_dual_correction, @@ -1278,19 +1360,18 @@ def sim_data(self) -> MODE_SIMULATION_DATA_TYPE: :class:`.SimulationData` object containing the effective index and mode fields. """ monitor_data = self.data - new_monitors = list(self.simulation.monitors) + [monitor_data.monitor] - new_simulation = self.simulation.copy(update=dict(monitors=new_monitors)) + new_monitors = [*list(self.simulation.monitors), monitor_data.monitor] + new_simulation = self.simulation.copy(update={"monitors": new_monitors}) if isinstance(new_simulation, Simulation): return SimulationData(simulation=new_simulation, data=(monitor_data,)) - elif isinstance(new_simulation, EMESimulation): + if isinstance(new_simulation, EMESimulation): return EMESimulationData( simulation=new_simulation, data=(monitor_data,), smatrix=None, port_modes=None ) - else: - raise SetupError( - "The 'simulation' provided does not correspond to any known " - "'AbstractSimulationData' type." - ) + raise SetupError( + "The 'simulation' provided does not correspond to any known " + "'AbstractSimulationData' type." + ) def _get_epsilon(self, freq: float) -> ArrayComplex4D: """Compute the epsilon tensor in the plane. Order of components is xx, xy, xz, yx, etc.""" @@ -1313,7 +1394,7 @@ def _tensorial_material_profile_modal_plane_tranform( # convert to into 3-by-3 representation for easier axis swap flat_shape = np.shape(mat_tensor) # 9 components flat - tensor_shape = [3, 3] + list(flat_shape[1:]) # 3-by-3 matrix + tensor_shape = [3, 3, *flat_shape[1:]] # 3-by-3 matrix mat_tensor = mat_tensor.reshape(tensor_shape) # swap axes to plane coordinates (normal_axis goes to z) @@ -1356,18 +1437,21 @@ def _diagonal_material_profile_modal_plane_tranform( def _solver_eps(self, freq: float) -> ArrayComplex4D: """Diagonal permittivity in the shape needed by solver, with normal axis rotated to z.""" - # Get diagonal epsilon components in the plane eps_tensor = self._get_epsilon(freq) # tranformation return self._tensorial_material_profile_modal_plane_tranform(eps_tensor, self.normal_axis) + @supports_local_subpixel def _solve_all_freqs( self, - coords: Tuple[ArrayFloat1D, ArrayFloat1D], - symmetry: Tuple[Symmetry, Symmetry], - ) -> Tuple[List[float], List[Dict[str, ArrayComplex4D]], List[EpsSpecType]]: + coords: tuple[ArrayFloat1D, ArrayFloat1D], + symmetry: tuple[Symmetry, Symmetry], + ) -> tuple[list[float], list[dict[str, ArrayComplex4D]], list[EpsSpecType]]: """Call the mode solver at all requested frequencies.""" + if tidy3d_extras["use_local_subpixel"]: + subpixel_ms = tidy3d_extras["mod"].SubpixelModeSolver.from_mode_solver(self) + return subpixel_ms._solve_all_freqs(coords=coords, symmetry=symmetry) fields = [] n_complex = [] @@ -1381,13 +1465,19 @@ def _solve_all_freqs( eps_spec.append(eps_spec_freq) return n_complex, fields, eps_spec + @supports_local_subpixel def _solve_all_freqs_relative( self, - coords: Tuple[ArrayFloat1D, ArrayFloat1D], - symmetry: Tuple[Symmetry, Symmetry], - basis_fields: List[Dict[str, ArrayComplex4D]], - ) -> Tuple[List[float], List[Dict[str, ArrayComplex4D]], List[EpsSpecType]]: + coords: tuple[ArrayFloat1D, ArrayFloat1D], + symmetry: tuple[Symmetry, Symmetry], + basis_fields: list[dict[str, ArrayComplex4D]], + ) -> tuple[list[float], list[dict[str, ArrayComplex4D]], list[EpsSpecType]]: """Call the mode solver at all requested frequencies.""" + if tidy3d_extras["use_local_subpixel"]: + subpixel_ms = tidy3d_extras["mod"].SubpixelModeSolver.from_mode_solver(self) + return subpixel_ms._solve_all_freqs_relative( + coords=coords, symmetry=symmetry, basis_fields=basis_fields + ) fields = [] n_complex = [] @@ -1426,9 +1516,9 @@ def _postprocess_solver_fields(solver_fields, normal_axis, plane, mode_spec, coo def _solve_single_freq( self, freq: float, - coords: Tuple[ArrayFloat1D, ArrayFloat1D], - symmetry: Tuple[Symmetry, Symmetry], - ) -> Tuple[float, Dict[str, ArrayComplex4D], EpsSpecType]: + coords: tuple[ArrayFloat1D, ArrayFloat1D], + symmetry: tuple[Symmetry, Symmetry], + ) -> tuple[float, dict[str, ArrayComplex4D], EpsSpecType]: """Call the mode solver at a single frequency. The fields are rotated from propagation coordinates back to global coordinates. @@ -1453,22 +1543,26 @@ def _solve_single_freq( ) return n_complex, fields, eps_spec - def _rotate_field_coords_inverse(self, field: FIELD) -> FIELD: + @classmethod + def _rotate_field_coords_inverse( + cls, field: FIELD, normal_axis: Axis, plane: MODE_PLANE_TYPE + ) -> FIELD: """Move the propagation axis to the z axis in the array.""" - f_x, f_y, f_z = np.moveaxis(field, source=1 + self.normal_axis, destination=3) - f_n, f_ts = self.plane.pop_axis((f_x, f_y, f_z), axis=self.normal_axis) - return np.stack(self.plane.unpop_axis(f_n, f_ts, axis=2), axis=0) + f_x, f_y, f_z = np.moveaxis(field, source=1 + normal_axis, destination=3) + f_n, f_ts = plane.pop_axis((f_x, f_y, f_z), axis=normal_axis) + return np.stack(plane.unpop_axis(f_n, f_ts, axis=2), axis=0) - def _postprocess_solver_fields_inverse(self, fields): + @classmethod + def _postprocess_solver_fields_inverse(cls, fields, normal_axis: Axis, plane: MODE_PLANE_TYPE): """Convert ``fields`` to ``solver_fields``. Doesn't change gauge.""" E = [fields[key] for key in ("Ex", "Ey", "Ez")] H = [fields[key] for key in ("Hx", "Hy", "Hz")] - (Ex, Ey, Ez) = self._rotate_field_coords_inverse(E) - (Hx, Hy, Hz) = self._rotate_field_coords_inverse(H) + (Ex, Ey, Ez) = cls._rotate_field_coords_inverse(E, normal_axis=normal_axis, plane=plane) + (Hx, Hy, Hz) = cls._rotate_field_coords_inverse(H, normal_axis=normal_axis, plane=plane) # apply -1 to H fields if a reflection was involved in the rotation - if self.normal_axis == 1: + if normal_axis == 1: Hx *= -1 Hy *= -1 Hz *= -1 @@ -1479,10 +1573,10 @@ def _postprocess_solver_fields_inverse(self, fields): def _solve_single_freq_relative( self, freq: float, - coords: Tuple[ArrayFloat1D, ArrayFloat1D], - symmetry: Tuple[Symmetry, Symmetry], - basis_fields: Dict[str, ArrayComplex4D], - ) -> Tuple[float, Dict[str, ArrayComplex4D], EpsSpecType]: + coords: tuple[ArrayFloat1D, ArrayFloat1D], + symmetry: tuple[Symmetry, Symmetry], + basis_fields: dict[str, ArrayComplex4D], + ) -> tuple[float, dict[str, ArrayComplex4D], EpsSpecType]: """Call the mode solver at a single frequency. Modes are computed as linear combinations of ``basis_fields``. """ @@ -1490,7 +1584,9 @@ def _solve_single_freq_relative( if not LOCAL_SOLVER_IMPORTED: raise ImportError(IMPORT_ERROR_MSG) - solver_basis_fields = self._postprocess_solver_fields_inverse(basis_fields) + solver_basis_fields = self._postprocess_solver_fields_inverse( + fields=basis_fields, normal_axis=self.normal_axis, plane=self.plane + ) solver_fields, n_complex, eps_spec = compute_modes( eps_cross=self._solver_eps(freq), @@ -1518,25 +1614,35 @@ def _rotate_field_coords(field: FIELD, normal_axis: Axis, plane: MODE_PLANE_TYPE @staticmethod def _weighted_coord_max( array: ArrayFloat2D, u: ArrayFloat1D, v: ArrayFloat1D - ) -> Tuple[int, int]: + ) -> tuple[int, int]: """2D argmax for an array weighted in both directions.""" if not np.all(np.isfinite(array)): # make sure the array is valid return 0, 0 - m = array * u.reshape(-1, 1) - i = np.arange(array.shape[0]) - i = (m * i.reshape(-1, 1)).sum() / m.sum() - i = int(0.5 + i) if np.isfinite(i) else 0 # in case m.sum() ~ 0 + m_i = array * u.reshape(-1, 1) + total_weight_i = m_i.sum() + + if total_weight_i == 0: + i = 0 + else: + indices_i = np.arange(array.shape[0]) + weighted_sum = (m_i * indices_i.reshape(-1, 1)).sum() + i = int(0.5 + weighted_sum / total_weight_i) - m = array * v - j = np.arange(array.shape[1]) - j = (m * j).sum() / m.sum() - j = int(0.5 + j) if np.isfinite(j) else 0 + m_j = array * v + total_weight_j = m_j.sum() + + if total_weight_j == 0: + j = 0 + else: + indices_j = np.arange(array.shape[1]) + weighted_sum = (m_j * indices_j).sum() + j = int(0.5 + weighted_sum / total_weight_j) return i, j @staticmethod - def _inverted_gauge(e_field: FIELD, diff_coords: Tuple[ArrayFloat1D, ArrayFloat1D]) -> bool: + def _inverted_gauge(e_field: FIELD, diff_coords: tuple[ArrayFloat1D, ArrayFloat1D]) -> bool: """Check if the lower xy region of the mode has a negative sign.""" dx, dy = diff_coords e_x, e_y = e_field[:2, :, :, 0] @@ -1549,18 +1655,17 @@ def _inverted_gauge(e_field: FIELD, diff_coords: Tuple[ArrayFloat1D, ArrayFloat1 while i > 0 and j > 0: if (e[:i, :j] > 0).all(): return False - elif (e[:i, :j] < 0).all(): + if (e[:i, :j] < 0).all(): return True - else: - threshold = abs_e[:i, :j].max() * 0.5 - i, j = ModeSolver._weighted_coord_max(e_2[:i, :j], dx[:i], dy[:j]) - if abs(e[i, j]) >= threshold: - return e[i, j] < 0 - # Do not close the window for 1D mode solvers - if e.shape[0] == 1: - i = 1 - elif e.shape[1] == 1: - j = 1 + threshold = abs_e[:i, :j].max() * 0.5 + i, j = ModeSolver._weighted_coord_max(e_2[:i, :j], dx[:i], dy[:j]) + if abs(e[i, j]) >= threshold: + return e[i, j] < 0 + # Do not close the window for 1D mode solvers + if e.shape[0] == 1: + i = 1 + elif e.shape[1] == 1: + j = 1 return False @staticmethod @@ -1569,8 +1674,8 @@ def _process_fields( mode_index: pydantic.NonNegativeInt, normal_axis: Axis, plane: MODE_PLANE_TYPE, - diff_coords: Tuple[ArrayFloat1D, ArrayFloat1D], - ) -> Tuple[FIELD, FIELD]: + diff_coords: tuple[ArrayFloat1D, ArrayFloat1D], + ) -> tuple[FIELD, FIELD]: """Transform solver fields to simulation axes and set gauge.""" # Separate E and H fields (in solver coordinates) @@ -1654,7 +1759,7 @@ def _grid_correction( Copy of the data with renormalized fields. """ normal_axis = plane.size.index(0.0) - normal_pos = plane.center[normal_axis] + normal_pos = float(plane.center[normal_axis]) normal_dim = "xyz"[normal_axis] # Primal and dual grid along the normal direction, @@ -1697,7 +1802,7 @@ def _is_tensorial(self) -> bool: return abs(self.mode_spec.angle_theta) > 0 or self._has_fully_anisotropic_media @cached_property - def _intersecting_media(self) -> List: + def _intersecting_media(self) -> list: """List of media (including simulation background) intersecting the mode plane.""" total_structures = [self.simulation.scene.background_structure] total_structures += list(self.simulation.structures) @@ -1738,6 +1843,8 @@ def _contain_good_conductor(self) -> bool: for medium in sim.scene.mediums: if medium.is_pec: return True + if medium.is_pmc: + return True if apply_sibc and isinstance(medium, LossyMetalMedium): return True return False @@ -1794,7 +1901,9 @@ def to_source( **kwargs, ) - def to_monitor(self, freqs: List[float] = None, name: str = None) -> ModeMonitor: + def to_monitor( + self, freqs: Optional[list[float]] = None, name: Optional[str] = None + ) -> ModeMonitor: """Creates :class:`ModeMonitor` from a :class:`ModeSolver` instance plus additional specifications. @@ -1830,7 +1939,9 @@ def to_monitor(self, freqs: List[float] = None, name: str = None) -> ModeMonitor name=name, ) - def to_mode_solver_monitor(self, name: str, colocate: bool = None) -> ModeSolverMonitor: + def to_mode_solver_monitor( + self, name: str, colocate: Optional[bool] = None + ) -> ModeSolverMonitor: """Creates :class:`ModeSolverMonitor` from a :class:`ModeSolver` instance. Parameters @@ -1891,15 +2002,15 @@ def sim_with_source( mode_source = self.to_source( mode_index=mode_index, direction=direction, source_time=source_time ) - new_sources = list(self.simulation.sources) + [mode_source] + new_sources = [*list(self.simulation.sources), mode_source] new_sim = self.simulation.updated_copy(sources=new_sources) return new_sim @require_fdtd_simulation def sim_with_monitor( self, - freqs: List[float] = None, - name: str = None, + freqs: Optional[list[float]] = None, + name: Optional[str] = None, ) -> Simulation: """Creates :class:`.Simulation` from a :class:`ModeSolver`. Creates a copy of the ModeSolver's original simulation with a mode monitor added corresponding to @@ -1921,7 +2032,7 @@ def sim_with_monitor( """ mode_monitor = self.to_monitor(freqs=freqs, name=name) - new_monitors = list(self.simulation.monitors) + [mode_monitor] + new_monitors = [*list(self.simulation.monitors), mode_monitor] new_sim = self.simulation.updated_copy(monitors=new_monitors) return new_sim @@ -1945,7 +2056,7 @@ def sim_with_mode_solver_monitor( from the ModeSolver instance and ``name``. """ mode_solver_monitor = self.to_mode_solver_monitor(name=name) - new_monitors = list(self.simulation.monitors) + [mode_solver_monitor] + new_monitors = [*list(self.simulation.monitors), mode_solver_monitor] new_sim = self.simulation.updated_copy(monitors=new_monitors) return new_sim @@ -1956,8 +2067,8 @@ def plot_field( scale: PlotScale = "lin", eps_alpha: float = 0.2, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, **sel_kwargs, ) -> Ax: @@ -2016,6 +2127,9 @@ def plot_field( def plot( self, ax: Ax = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + fill_structures: bool = True, **patch_kwargs, ) -> Ax: """Plot the mode plane simulation's components. @@ -2024,6 +2138,12 @@ def plot( ---------- ax : matplotlib.axes._subplots.Axes = None Matplotlib axes to plot on, if not specified, one is created. + hlim : Tuple[float, float] = None + The x range if plotting on xy or xz planes, y range if plotting on yz plane. + vlim : Tuple[float, float] = None + The z range if plotting on xz or yz planes, y plane if plotting on xy plane. + fill_structures : bool = True + Whether to fill structures with color or just draw outlines. Returns ------- @@ -2038,20 +2158,26 @@ def plot( """ # Get the mode plane normal axis, center, and limits. - a_center, h_lim, v_lim, _ = self._center_and_lims( + a_center, hlim_plane, vlim_plane, _ = self._center_and_lims( simulation=self.simulation, plane=self.plane ) + if hlim is None: + hlim = hlim_plane + if vlim is None: + vlim = vlim_plane + ax = self.simulation.plot( x=a_center[0], y=a_center[1], z=a_center[2], - hlim=h_lim, - vlim=v_lim, + hlim=hlim, + vlim=vlim, source_alpha=0, monitor_alpha=0, lumped_element_alpha=0, ax=ax, + fill_structures=fill_structures, **patch_kwargs, ) @@ -2059,8 +2185,8 @@ def plot( def plot_eps( self, - freq: float = None, - alpha: float = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot the mode plane simulation's components. @@ -2113,8 +2239,8 @@ def plot_eps( def plot_structures_eps( self, - freq: float = None, - alpha: float = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, @@ -2203,7 +2329,7 @@ def plot_grid( ) @classmethod - def _plane_grid(cls, simulation: Simulation, plane: Box) -> Tuple[Coords, Coords]: + def _plane_grid(cls, simulation: Simulation, plane: Box) -> tuple[Coords, Coords]: """Plane grid for mode solver.""" # Get the mode plane normal axis, center, and limits. _, _, _, t_axes = cls._center_and_lims(simulation=simulation, plane=plane) @@ -2219,7 +2345,7 @@ def _plane_grid(cls, simulation: Simulation, plane: Box) -> Tuple[Coords, Coords @classmethod def _effective_num_pml( cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec - ) -> Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: + ) -> tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: """Number of cells of the mode solver pml.""" coord_0, coord_1 = cls._plane_grid(simulation=simulation, plane=plane) @@ -2233,9 +2359,9 @@ def _effective_num_pml( @classmethod def _pml_thickness( cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec - ) -> Tuple[ - Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat], - Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat], + ) -> tuple[ + tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat], + tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat], ]: """Thickness of the mode solver pml in the form ((plus0, minus0), (plus1, minus1)) @@ -2273,7 +2399,7 @@ def _pml_thickness( @classmethod def _mode_plane_size( cls, simulation: Simulation, plane: Box - ) -> Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: + ) -> tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: """The size of the mode plane intersected with the simulation.""" _, h_lim, v_lim, _ = cls._center_and_lims(simulation=simulation, plane=plane) return h_lim[1] - h_lim[0], v_lim[1] - v_lim[0] @@ -2281,7 +2407,7 @@ def _mode_plane_size( @classmethod def _mode_plane_size_no_pml( cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec - ) -> Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: + ) -> tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat]: """The size of the remaining portion of the mode plane, after the pml has been removed.""" size = cls._mode_plane_size(simulation=simulation, plane=plane) @@ -2315,6 +2441,10 @@ def _plot_pml( cls, simulation: Simulation, plane: Box, mode_spec: ModeSpec, ax: Ax = None ) -> Ax: """Plot the mode plane absorbing boundaries.""" + + from matplotlib.collections import PatchCollection + from matplotlib.patches import Rectangle + # Get the mode plane normal axis, center, and limits. _, h_lim, v_lim, _ = cls._center_and_lims(simulation=simulation, plane=plane) @@ -2364,7 +2494,7 @@ def _plot_pml( return ax @staticmethod - def _center_and_lims(simulation: Simulation, plane: Box) -> Tuple[List, List, List, List]: + def _center_and_lims(simulation: Simulation, plane: Box) -> tuple[list, list, list, list]: """Get the mode plane center and limits.""" normal_axis = plane.size.index(0.0) @@ -2458,6 +2588,7 @@ def reduced_simulation_copy(self): region=new_sim_box, monitors=[], sources=[], + warn_symmetry_expansion=False, # we already warn upon mode solver creation grid_spec="identical", boundary_spec=new_bspec, remove_outside_custom_mediums=True, diff --git a/tidy3d/components/mode/simulation.py b/tidy3d/components/mode/simulation.py index 290bae48c5..9a0300c148 100644 --- a/tidy3d/components/mode/simulation.py +++ b/tidy3d/components/mode/simulation.py @@ -2,31 +2,29 @@ from __future__ import annotations -from typing import Optional, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd -from ...constants import C_0 -from ...exceptions import SetupError, ValidationError -from ...log import log -from ..base import cached_property -from ..boundary import Boundary, BoundarySpec -from ..geometry.base import Box -from ..grid.grid import Grid -from ..grid.grid_spec import GridSpec -from ..mode_spec import ModeSpec -from ..monitor import ModeMonitor, ModeSolverMonitor, PermittivityMonitor -from ..simulation import AbstractYeeGridSimulation, Simulation, validate_boundaries_for_zero_dims -from ..source.field import ModeSource -from ..types import ( - TYPE_TAG_STR, - Ax, - Direction, - EMField, - FreqArray, +from tidy3d.components.base import cached_property +from tidy3d.components.boundary import BoundarySpec +from tidy3d.components.geometry.base import Box +from tidy3d.components.grid.grid import Grid +from tidy3d.components.grid.grid_spec import GridSpec +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor, PermittivityMonitor +from tidy3d.components.simulation import ( + AbstractYeeGridSimulation, + Simulation, + validate_boundaries_for_zero_dims, ) -from ..validators import validate_mode_plane_radius +from tidy3d.components.source.field import ModeSource +from tidy3d.components.types import TYPE_TAG_STR, Ax, Direction, EMField, FreqArray +from tidy3d.constants import C_0 +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .mode_solver import ModeSolver ModeSimulationMonitorType = PermittivityMonitor @@ -138,7 +136,7 @@ class ModeSimulation(AbstractYeeGridSimulation): "primal grid nodes). Default is ``True``.", ) - fields: Tuple[EMField, ...] = pd.Field( + fields: tuple[EMField, ...] = pd.Field( ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], title="Field Components", description="Collection of field components to store in the monitor. Note that some " @@ -156,14 +154,14 @@ class ModeSimulation(AbstractYeeGridSimulation): "apply PML layers in the mode solver.", ) - monitors: Tuple[ModeSimulationMonitorType, ...] = pd.Field( + monitors: tuple[ModeSimulationMonitorType, ...] = pd.Field( (), title="Monitors", description="Tuple of monitors in the simulation. " "Note: monitor names are used to access data after simulation is run.", ) - sources: Tuple[()] = pd.Field( + sources: tuple[()] = pd.Field( (), title="Sources", description="Sources in the simulation. Note: sources are not supported in mode " @@ -215,23 +213,8 @@ def plane_in_sim_bounds(cls, val, values): raise SetupError("'ModeSimulation.plane' must intersect 'ModeSimulation.geometry.") return val - @pd.validator("boundary_spec", always=True) - def boundaries_for_zero_dims(cls, val, values): - """Replace with periodic boundary along zero-size dimensions.""" - boundaries = [val.x, val.y, val.z] - size = values.get("size") - - for dim, size_dim in enumerate(size): - if size_dim == 0: - boundaries[dim] = Boundary.periodic() - - return BoundarySpec(x=boundaries[0], y=boundaries[1], z=boundaries[2]) - def _post_init_validators(self) -> None: """Call validators taking `self` that get run after init.""" - validate_mode_plane_radius( - mode_spec=self.mode_spec, plane=self.plane, msg_prefix="'ModeSimulation'" - ) _ = self._mode_solver _ = self.grid @@ -251,6 +234,9 @@ def run_local(self): """Run locally.""" from .data.sim_data import ModeSimulationData + # repeat the calculation every time, in case use_local_subpixel changed + self._invalidate_solver_cache() + modes_raw = self._mode_solver.data_raw return ModeSimulationData(simulation=self, modes_raw=modes_raw) @@ -375,6 +361,75 @@ def from_mode_solver( ) return mode_sim + def plot( + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + source_alpha: Optional[float] = 0, + monitor_alpha: Optional[float] = 0, + lumped_element_alpha: Optional[float] = 0, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + fill_structures: bool = True, + **patch_kwargs, + ) -> Ax: + """Plot the mode simulation. If any of ``x``, ``y``, or ``z`` is provided, the potentially + larger FDTD simulation containing the mode plane is plotted at the desired location. + Otherwise, the mode plane is plotted by default. + + Parameters + ---------- + fill_structures : bool = True + Whether to fill structures with color or just draw outlines. + x : float = None + position of plane in x direction, only one of x, y, z must be specified to define plane. + y : float = None + position of plane in y direction, only one of x, y, z must be specified to define plane. + z : float = None + position of plane in z direction, only one of x, y, z must be specified to define plane. + source_alpha : float = 0 + Opacity of the sources. If ``None``, uses Tidy3d default. + monitor_alpha : float = 0 + Opacity of the monitors. If ``None``, uses Tidy3d default. + lumped_element_alpha : float = 0 + Opacity of the lumped elements. If ``None``, uses Tidy3d default. + ax : matplotlib.axes._subplots.Axes = None + Matplotlib axes to plot on, if not specified, one is created. + hlim : Tuple[float, float] = None + The x range if plotting on xy or xz planes, y range if plotting on yz plane. + vlim : Tuple[float, float] = None + The z range if plotting on xz or yz planes, y plane if plotting on xy plane. + + Returns + ------- + matplotlib.axes._subplots.Axes + The supplied or created matplotlib axes. + """ + + if x is not None or y is not None or z is not None: + return super().plot( + x=x, + y=y, + z=z, + ax=ax, + source_alpha=source_alpha, + monitor_alpha=monitor_alpha, + lumped_element_alpha=lumped_element_alpha, + hlim=hlim, + vlim=vlim, + fill_structures=fill_structures, + **patch_kwargs, + ) + return self._mode_solver.plot( + ax=ax, + hlim=hlim, + vlim=vlim, + fill_structures=fill_structures, + **patch_kwargs, + ) + def plot_mode_plane( self, ax: Ax = None, @@ -403,8 +458,8 @@ def plot_mode_plane( def plot_eps_mode_plane( self, - freq: float = None, - alpha: float = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot the mode plane simulation's components. @@ -436,8 +491,8 @@ def plot_eps_mode_plane( def plot_structures_eps_mode_plane( self, - freq: float = None, - alpha: float = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, @@ -520,4 +575,4 @@ def plot_pml_mode_plane( def validate_pre_upload(self, source_required: bool = False): self._mode_solver.validate_pre_upload(source_required=source_required) - _boundaries_for_zero_dims = validate_boundaries_for_zero_dims() + _boundaries_for_zero_dims = validate_boundaries_for_zero_dims(warn_on_change=False) diff --git a/tidy3d/components/mode/solver.py b/tidy3d/components/mode/solver.py index 2cd12ef4de..5755647a31 100644 --- a/tidy3d/components/mode/solver.py +++ b/tidy3d/components/mode/solver.py @@ -1,15 +1,15 @@ """Mode solver for propagating EM modes.""" -from typing import Tuple +from __future__ import annotations + +from typing import TYPE_CHECKING, Optional import numpy as np -import scipy.linalg as linalg -import scipy.sparse as sp -import scipy.sparse.linalg as spl -from ...constants import C_0, ETA_0, fp_eps, pec_val -from ..base import Tidy3dBaseModel -from ..types import EpsSpecType, ModeSolverType, Numpy +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.types import EpsSpecType, ModeSolverType, Numpy +from tidy3d.constants import C_0, ETA_0, fp_eps, pec_val + from .derivatives import create_d_matrices as d_mats from .derivatives import create_s_matrices as s_mats from .transforms import angled_transform, radial_transform @@ -27,6 +27,10 @@ # Good conductor permittivity cut-off value. Let it be as large as possible so long as not causing overflow in # double precision. This value is very heuristic. GOOD_CONDUCTOR_CUT_OFF = 1e70 + +if TYPE_CHECKING: + from scipy import sparse as sp + # Consider a material to be good conductor if |ep| (or |mu|) > GOOD_CONDUCTOR_THRESHOLD * |pec_val| GOOD_CONDUCTOR_THRESHOLD = 0.9 @@ -49,8 +53,8 @@ def compute_modes( symmetry=(0, 0), direction="+", solver_basis_fields=None, - plane_center: tuple[float, float] = None, - ) -> Tuple[Numpy, Numpy, EpsSpecType]: + plane_center: Optional[tuple[float, float]] = None, + ) -> tuple[Numpy, Numpy, EpsSpecType]: """ Solve for the modes of a waveguide cross-section. @@ -249,7 +253,7 @@ def compute_modes( "Shape mismatch between 'basis_fields' and requested mode data. " "Make sure the mode solvers are set up the same, and that the " "basis mode solver data has 'colocate=False'." - ) + ) from None if split_curl_scaling is not None: basis_E = cls.split_curl_field_postprocess_inverse(split_curl_scaling, basis_E) jac_e_inv = np.moveaxis( @@ -450,6 +454,7 @@ def trim_small_values(cls, mat: sp.csr_matrix, tol: float) -> sp.csr_matrix: max_element = np.amax(np.abs(mat)) mat.data *= np.logical_or(np.abs(mat.data) / max_element > tol, np.abs(mat.data) > tol) mat.eliminate_zeros() + return mat @classmethod def solver_diagonal( @@ -465,12 +470,15 @@ def solver_diagonal( basis_E, ): """EM eigenmode solver assuming ``eps`` and ``mu`` are diagonal everywhere.""" + import scipy.sparse as sp + import scipy.sparse.linalg as spl # code associated with these options is included below in case it's useful in the future enable_preconditioner = False analyze_conditioning = False + _threshold = 0.9 * np.abs(pec_val) - def incidence_matrix_for_pec(eps_vec, threshold=0.9 * np.abs(pec_val)): + def incidence_matrix_for_pec(eps_vec, threshold=_threshold): """Incidence matrix indicating non-PEC entries associated with 'eps_vec'.""" nnz = eps_vec[np.abs(eps_vec) < threshold] eps_nz = eps_vec.copy() @@ -595,10 +603,10 @@ def conditional_inverted_vec(eps_vec, threshold=1): aac = mat * mat.conjugate().T diff = aca - aac print( - f"inf-norm: A*A: {spl.norm(aca, ord=np.inf)}, AA*: {spl.norm(aac, ord=np.inf)}, nonnormality: {spl.norm(diff, ord=np.inf)}, relative nonnormality: {spl.norm(diff, ord=np.inf)/spl.norm(aca, ord=np.inf)}" + f"inf-norm: A*A: {spl.norm(aca, ord=np.inf)}, AA*: {spl.norm(aac, ord=np.inf)}, nonnormality: {spl.norm(diff, ord=np.inf)}, relative nonnormality: {spl.norm(diff, ord=np.inf) / spl.norm(aca, ord=np.inf)}" ) print( - f"fro-norm: A*A: {spl.norm(aca, ord='fro')}, AA*: {spl.norm(aac, ord='fro')}, nonnormality: {spl.norm(diff, ord='fro')}, relative nonnormality: {spl.norm(diff, ord='fro')/spl.norm(aca, ord='fro')}" + f"fro-norm: A*A: {spl.norm(aca, ord='fro')}, AA*: {spl.norm(aac, ord='fro')}, nonnormality: {spl.norm(diff, ord='fro')}, relative nonnormality: {spl.norm(diff, ord='fro') / spl.norm(aca, ord='fro')}" ) # preprocess basis modes @@ -681,6 +689,7 @@ def solver_tensorial( cls, eps, mu, der_mats, num_modes, neff_guess, vec_init, mat_precision, direction ): """EM eigenmode solver assuming ``eps`` or ``mu`` have off-diagonal elements.""" + import scipy.sparse as sp mode_solver_type = "tensorial" N = eps.shape[-1] @@ -826,6 +835,7 @@ def solver_eigs( Number of eigenmodes to compute. guess_value : float, optional """ + import scipy.sparse.linalg as spl values, vectors = spl.eigs( mat, k=num_modes, sigma=guess_value, tol=TOL_EIGS, v0=vec_init, M=M @@ -864,6 +874,7 @@ def solver_eigs_relative( Number of eigenmodes to compute. guess_value : float, optional """ + import scipy.linalg as linalg basis, _ = np.linalg.qr(basis_vecs) mat_basis = np.conj(basis.T) @ mat @ basis @@ -874,22 +885,25 @@ def solver_eigs_relative( @classmethod def isinstance_complex(cls, vec_or_mat, tol=TOL_COMPLEX): - """Check if a numpy array or scipy csr_matrix has complex component by looking at + """Check if a numpy array or scipy.sparse.csr_matrix has complex component by looking at norm(x.imag)/norm(x)>TOL_COMPLEX Parameters ---------- vec_or_mat : Union[np.ndarray, sp.csr_matrix] """ + import scipy.sparse.linalg as spl + from scipy.sparse import csr_matrix if isinstance(vec_or_mat, np.ndarray): return np.linalg.norm(vec_or_mat.imag) / (np.linalg.norm(vec_or_mat) + fp_eps) > tol - if isinstance(vec_or_mat, sp.csr_matrix): + if isinstance(vec_or_mat, csr_matrix): mat_norm = spl.norm(vec_or_mat) mat_imag_norm = spl.norm(vec_or_mat.imag) return mat_imag_norm / (mat_norm + fp_eps) > tol - - raise RuntimeError("Variable type should be either numpy array or scipy csr_matrix.") + raise RuntimeError( + f"Variable type should be either numpy array or scipy.sparse.csr_matrix, got {type(vec_or_mat)}." + ) @classmethod def type_conversion(cls, vec_or_mat, new_dtype): @@ -1044,6 +1058,6 @@ def mode_plane_contain_good_conductor(material_response) -> bool: return np.any(np.abs(material_response) > GOOD_CONDUCTOR_THRESHOLD * np.abs(pec_val)) -def compute_modes(*args, **kwargs) -> Tuple[Numpy, Numpy, str]: +def compute_modes(*args, **kwargs) -> tuple[Numpy, Numpy, str]: """A wrapper around ``EigSolver.compute_modes``, which is used in ``ModeSolver``.""" return EigSolver.compute_modes(*args, **kwargs) diff --git a/tidy3d/components/mode/transforms.py b/tidy3d/components/mode/transforms.py index 53372b395f..c498be1af9 100644 --- a/tidy3d/components/mode/transforms.py +++ b/tidy3d/components/mode/transforms.py @@ -8,6 +8,8 @@ Similarly, the jacobian for mu and H is evaluated at the r' positions of H-field components. Currently, the half-step offset in w is ignored, which should be a pretty good approximation.""" +from __future__ import annotations + import numpy as np diff --git a/tidy3d/components/mode_spec.py b/tidy3d/components/mode_spec.py index 4f63465bce..0f85bb47c0 100644 --- a/tidy3d/components/mode_spec.py +++ b/tidy3d/components/mode_spec.py @@ -1,16 +1,19 @@ """Defines specification for mode solver.""" +from __future__ import annotations + from math import isclose -from typing import Tuple, Union +from typing import Literal, Union import numpy as np import pydantic.v1 as pd -from ..constants import GLANCING_CUTOFF, MICROMETER, RADIAN, fp_eps -from ..exceptions import SetupError, ValidationError -from ..log import log +from tidy3d.constants import GLANCING_CUTOFF, MICROMETER, RADIAN, fp_eps +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .base import Tidy3dBaseModel, skip_if_fields_missing -from .types import Axis2D, Literal, TrackFreq +from .types import Axis2D, TrackFreq GROUP_INDEX_STEP = 0.005 @@ -65,7 +68,7 @@ class ModeSpec(Tidy3dBaseModel): None, title="Target effective index", description="Guess for effective index of the mode." ) - num_pml: Tuple[pd.NonNegativeInt, pd.NonNegativeInt] = pd.Field( + num_pml: tuple[pd.NonNegativeInt, pd.NonNegativeInt] = pd.Field( (0, 0), title="Number of PML layers", description="Number of standard pml layers to add in the two tangential axes.", @@ -103,11 +106,11 @@ class ModeSpec(Tidy3dBaseModel): ) precision: Literal["auto", "single", "double"] = pd.Field( - "auto", + "double", title="single, double, or automatic precision in mode solver", description="The solver will be faster and using less memory under " "single precision, but more accurate under double precision. " - "With the default ``'auto'``, apply double precision if the simulation contains a good " + "Choose ``'auto'`` to apply double precision if the simulation contains a good " "conductor, single precision otherwise.", ) diff --git a/tidy3d/components/monitor.py b/tidy3d/components/monitor.py index e16fc13c70..1ad5cef331 100644 --- a/tidy3d/components/monitor.py +++ b/tidy3d/components/monitor.py @@ -1,14 +1,17 @@ """Objects that define how data is recorded from simulation.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pydantic -from ..constants import HERTZ, MICROMETER, RADIAN, SECOND, inf -from ..exceptions import SetupError, ValidationError -from ..log import log +from tidy3d.constants import HERTZ, MICROMETER, RADIAN, SECOND, inf +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .apodization import ApodizationSpec from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing from .base_sim.monitor import AbstractMonitor @@ -48,7 +51,7 @@ class Monitor(AbstractMonitor): """Abstract base class for monitors.""" - interval_space: Tuple[Literal[1], Literal[1], Literal[1]] = pydantic.Field( + interval_space: tuple[Literal[1], Literal[1], Literal[1]] = pydantic.Field( (1, 1, 1), title="Spatial Interval", description="Number of grid step intervals between monitor recordings. If equal to 1, " @@ -191,7 +194,7 @@ def stop_greater_than_start(cls, val, values): raise SetupError("Monitor start time is greater than stop time.") return val - def time_inds(self, tmesh: ArrayFloat1D) -> Tuple[int, int]: + def time_inds(self, tmesh: ArrayFloat1D) -> tuple[int, int]: """Compute the starting and stopping index of the monitor in a given discrete time mesh.""" tmesh = np.array(tmesh) @@ -230,13 +233,13 @@ def num_steps(self, tmesh: ArrayFloat1D) -> int: class AbstractFieldMonitor(Monitor, ABC): """:class:`Monitor` that records electromagnetic field data as a function of x,y,z.""" - fields: Tuple[EMField, ...] = pydantic.Field( + fields: tuple[EMField, ...] = pydantic.Field( ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], title="Field Components", description="Collection of field components to store in the monitor.", ) - interval_space: Tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( + interval_space: tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( pydantic.Field( (1, 1, 1), title="Spatial Interval", @@ -278,14 +281,14 @@ class AbstractAuxFieldMonitor(Monitor, ABC): :class:`.TwoPhotonAbsorption` uses `Nfx`, `Nfy`, and `Nfz` for the free-carrier density.""" - fields: Tuple[AuxField, ...] = pydantic.Field( + fields: tuple[AuxField, ...] = pydantic.Field( (), title="Aux Field Components", description="Collection of auxiliary field components to store in the monitor. " "Auxiliary fields which are not present in the simulation will be zero.", ) - interval_space: Tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( + interval_space: tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( pydantic.Field( (1, 1, 1), title="Spatial Interval", @@ -351,9 +354,9 @@ class AbstractModeMonitor(PlanarMonitor, FreqMonitor): def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **patch_kwargs, ) -> Ax: @@ -385,7 +388,7 @@ def plot( return ax @cached_property - def _dir_arrow(self) -> Tuple[float, float, float]: + def _dir_arrow(self) -> tuple[float, float, float]: """Source direction normal vector in cartesian coordinates.""" dx = np.cos(self.mode_spec.angle_phi) * np.sin(self.mode_spec.angle_theta) dy = np.sin(self.mode_spec.angle_phi) * np.sin(self.mode_spec.angle_theta) @@ -565,7 +568,7 @@ class PermittivityMonitor(FreqMonitor): "physical meaning - they do not correspond to the subpixel-averaged ones.", ) - interval_space: Tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( + interval_space: tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( pydantic.Field( (1, 1, 1), title="Spatial Interval", @@ -599,7 +602,7 @@ class SurfaceIntegrationMonitor(Monitor, ABC): "Applies to surface monitors only, and defaults to ``'+'`` if not provided.", ) - exclude_surfaces: Tuple[BoxSurface, ...] = pydantic.Field( + exclude_surfaces: tuple[BoxSurface, ...] = pydantic.Field( None, title="Excluded Surfaces", description="Surfaces to exclude in the integration, if a volume monitor.", @@ -796,7 +799,7 @@ class ModeSolverMonitor(AbstractModeMonitor): "dimension.", ) - fields: Tuple[EMField, ...] = pydantic.Field( + fields: tuple[EMField, ...] = pydantic.Field( ["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"], title="Field Components", description="Collection of field components to store in the monitor. Note that some " @@ -891,7 +894,7 @@ class AbstractFieldProjectionMonitor(SurfaceIntegrationMonitor, FreqMonitor): "in the far field of the device.", ) - interval_space: Tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( + interval_space: tuple[pydantic.PositiveInt, pydantic.PositiveInt, pydantic.PositiveInt] = ( pydantic.Field( (1, 1, 1), title="Spatial Interval", @@ -906,7 +909,7 @@ class AbstractFieldProjectionMonitor(SurfaceIntegrationMonitor, FreqMonitor): ) ) - window_size: Tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat] = pydantic.Field( + window_size: tuple[pydantic.NonNegativeFloat, pydantic.NonNegativeFloat] = pydantic.Field( (0, 0), title="Spatial filtering window size", description="Size of the transition region of the windowing function used to ensure that " @@ -961,7 +964,7 @@ def window_size_leq_one(cls, val, values): return val @property - def projection_surfaces(self) -> Tuple[FieldProjectionSurface, ...]: + def projection_surfaces(self) -> tuple[FieldProjectionSurface, ...]: """Surfaces of the monitor where near fields will be recorded for subsequent projection.""" surfaces = self.integration_surfaces return [ @@ -985,7 +988,7 @@ def local_origin(self) -> Coordinate: return self.center return self.custom_origin - def window_parameters(self, custom_bounds: Bound = None) -> Tuple[Size, Coordinate, Coordinate]: + def window_parameters(self, custom_bounds: Bound = None) -> tuple[Size, Coordinate, Coordinate]: """Return the physical size of the window transition region based on the monitor's size and optional custom bounds (useful in case the monitor has infinite dimensions). The window size is returned in 3D. Also returns the coordinate where the transition region beings on diff --git a/tidy3d/components/parameter_perturbation.py b/tidy3d/components/parameter_perturbation.py index 20b4e5d8b4..c20ea5889a 100644 --- a/tidy3d/components/parameter_perturbation.py +++ b/tidy3d/components/parameter_perturbation.py @@ -4,24 +4,27 @@ import functools from abc import ABC, abstractmethod -from typing import Callable, List, Optional, Tuple, Union +from typing import Callable, Optional, Union -try: - import matplotlib.pyplot as plt -except ImportError: - pass import numpy as np import pydantic.v1 as pd import xarray as xr -from ..components.data.validators import validate_no_nans -from ..components.types import TYPE_TAG_STR, ArrayLike, Ax, Complex, FieldVal, InterpMethod -from ..components.viz import add_ax_if_none -from ..constants import C_0, CMCUBE, EPSILON_0, HERTZ, KELVIN, PERCMCUBE, inf -from ..exceptions import DataError -from ..log import log +from tidy3d.components.data.validators import validate_no_nans +from tidy3d.components.types import TYPE_TAG_STR, ArrayLike, Ax, Complex, FieldVal, InterpMethod +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import C_0, CMCUBE, EPSILON_0, HERTZ, KELVIN, PERCMCUBE, inf +from tidy3d.exceptions import DataError +from tidy3d.log import log + from .base import Tidy3dBaseModel, cached_property -from .data.data_array import ChargeDataArray, HeatDataArray, IndexedDataArray, SpatialDataArray +from .data.data_array import ( + ChargeDataArray, + HeatDataArray, + IndexedDataArray, + PerturbationCoefficientDataArray, + SpatialDataArray, +) from .data.unstructured.base import UnstructuredGridDataset from .data.utils import ( CustomSpatialDataType, @@ -38,7 +41,7 @@ class AbstractPerturbation(ABC, Tidy3dBaseModel): @cached_property @abstractmethod - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[Complex, Complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[Complex, Complex]]: """Perturbation range.""" @cached_property @@ -47,7 +50,7 @@ def is_complex(self) -> bool: """Whether perturbation is complex valued.""" @staticmethod - def _linear_range(interval: Tuple[float, float], ref: float, coeff: Union[float, Complex]): + def _linear_range(interval: tuple[float, float], ref: float, coeff: Union[float, Complex]): """Find value range for a linear perturbation.""" if coeff in (0, 0j): # to avoid 0*inf return np.array([0, 0]) @@ -118,7 +121,7 @@ def _sample( class HeatPerturbation(AbstractPerturbation): """Abstract class for heat perturbation.""" - temperature_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + temperature_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( (0, inf), title="Temperature range", description="Temperature range in which perturbation model is valid.", @@ -236,7 +239,7 @@ class LinearHeatPerturbation(HeatPerturbation): ) @cached_property - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[Complex, Complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[Complex, Complex]]: """Range of possible perturbation values in the provided ``temperature_range``.""" return self._linear_range(self.temperature_range, self.temperature_ref, self.coeff) @@ -315,7 +318,7 @@ class CustomHeatPerturbation(HeatPerturbation): description="Sampled perturbation values.", ) - temperature_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + temperature_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( None, title="Temperature range", description="Temperature range in which perturbation model is valid. For " @@ -333,7 +336,7 @@ class CustomHeatPerturbation(HeatPerturbation): _no_nans = validate_no_nans("perturbation_values") @cached_property - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[Complex, Complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[Complex, Complex]]: """Range of possible parameter perturbation values.""" return np.min(self.perturbation_values).item(), np.max(self.perturbation_values).item() @@ -480,13 +483,13 @@ def _sample( class ChargePerturbation(AbstractPerturbation): """Abstract class for charge perturbation.""" - electron_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + electron_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( (0, inf), title="Electron Density Range", description="Range of electrons densities in which perturbation model is valid.", ) - hole_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + hole_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( (0, inf), title="Hole Density Range", description="Range of holes densities in which perturbation model is valid.", @@ -583,7 +586,7 @@ def plot( else: e_mesh, h_mesh = np.meshgrid(electron_density, hole_density, indexing="ij") pc = ax.pcolormesh(e_mesh, h_mesh, values, shading="gouraud") - plt.colorbar(pc, ax=ax) + ax.figure.colorbar(pc, ax=ax) ax.set_xlabel("electron density (1/cm^3)") ax.set_ylabel("hole density (1/cm^3)") @@ -658,7 +661,7 @@ class LinearChargePerturbation(ChargePerturbation): ) @cached_property - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[Complex, Complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[Complex, Complex]]: """Range of possible perturbation values within provided ``electron_range`` and ``hole_range``. """ @@ -794,7 +797,7 @@ class CustomChargePerturbation(ChargePerturbation): description="2D array (vs electron and hole densities) of sampled perturbation values.", ) - electron_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + electron_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( None, title="Electron Density Range", description="Range of electrons densities in which perturbation model is valid. For " @@ -802,7 +805,7 @@ class CustomChargePerturbation(ChargePerturbation): "provided ``perturbation_values``", ) - hole_range: Tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( + hole_range: tuple[pd.NonNegativeFloat, pd.NonNegativeFloat] = pd.Field( None, title="Hole Density Range", description="Range of holes densities in which perturbation model is valid. For " @@ -819,7 +822,7 @@ class CustomChargePerturbation(ChargePerturbation): _no_nans = validate_no_nans("perturbation_values") @cached_property - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[complex, complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[complex, complex]]: """Range of possible parameter perturbation values.""" return np.min(self.perturbation_values).item(), np.max(self.perturbation_values).item() @@ -935,6 +938,10 @@ def sample( if isinstance(h_vals, UnstructuredGridDataset): h_vals = h_vals.values + # Needed to avoid error in some xarray / numpy versions + e_vals = e_vals.item() if e_vals.size == 1 else e_vals + h_vals = h_vals.item() if h_vals.size == 1 else h_vals + # note that the dimensionality of this operation differs depending on whether xarrays # or simple unlabeled arrays are provided: # - for unlabeled arrays, values are broadcasted @@ -1021,7 +1028,7 @@ def _check_not_empty(cls, values): return values @cached_property - def perturbation_list(self) -> List[PerturbationType]: + def perturbation_list(self) -> list[PerturbationType]: """Provided perturbations as a list.""" perturb_list = [] for p in [self.heat, self.charge]: @@ -1030,7 +1037,7 @@ def perturbation_list(self) -> List[PerturbationType]: return perturb_list @cached_property - def perturbation_range(self) -> Union[Tuple[float, float], Tuple[Complex, Complex]]: + def perturbation_range(self) -> Union[tuple[float, float], tuple[Complex, Complex]]: """Range of possible parameter perturbation values due to both heat and charge effects.""" prange = np.zeros(2) @@ -1252,277 +1259,261 @@ class NedeljkovicSorefMashanovich(AbstractDeltaModel): ------- """ - perturb_coeffs = xr.Dataset( - { - "a": ( - "wvl", - [ - 3.48e-22, - 8.88e-21, - 3.22e-20, - 1.67e-20, - 6.29e-21, - 3.10e-21, - 7.45e-22, - 2.16e-22, - 9.28e-23, - 4.58e-23, - 3.26e-23, - 2.70e-23, - 2.25e-23, - 1.36e-23, - 1.85e-23, - 3.05e-23, - 4.08e-23, - 4.14e-23, - 3.81e-23, - 4.23e-23, - 5.81e-23, - 8.20e-23, - 1.13e-22, - 1.22e-22, - 1.09e-22, - 1.20e-22, - 1.62e-22, - ], - ), - "b": ( - "wvl", - [ - 1.229, - 1.167, - 1.149, - 1.169, - 1.193, - 1.210, - 1.245, - 1.277, - 1.299, - 1.319, - 1.330, - 1.338, - 1.345, - 1.359, - 1.354, - 1.345, - 1.340, - 1.341, - 1.344, - 1.344, - 1.338, - 1.331, - 1.325, - 1.324, - 1.328, - 1.327, - 1.321, - ], - ), - "c": ( - "wvl", - [ - 1.02e-19, - 5.84e-20, - 6.21e-20, - 8.08e-20, - 3.40e-20, - 6.05e-20, - 5.43e-20, - 5.58e-20, - 6.65e-20, - 8.53e-20, - 1.53e-19, - 1.22e-19, - 1.29e-19, - 9.99e-20, - 1.32e-19, - 1.57e-18, - 1.45e-18, - 1.70e-18, - 1.25e-18, - 8.14e-19, - 1.55e-18, - 4.81e-18, - 4.72e-18, - 2.09e-18, - 1.16e-18, - 2.01e-18, - 7.52e-18, - ], - ), - "d": ( - "wvl", - [ - 1.089, - 1.109, - 1.119, - 1.123, - 1.151, - 1.145, - 1.153, - 1.158, - 1.160, - 1.159, - 1.149, - 1.158, - 1.160, - 1.170, - 1.167, - 1.111, - 1.115, - 1.115, - 1.125, - 1.137, - 1.124, - 1.100, - 1.102, - 1.124, - 1.140, - 1.130, - 1.101, - ], - ), - "p": ( - "wvl", - [ - 2.98e-22, - 5.40e-22, - 1.91e-21, - 5.70e-21, - 6.57e-21, - 6.95e-21, - 7.25e-21, - 1.19e-20, - 2.46e-20, - 3.64e-20, - 4.96e-20, - 5.91e-20, - 5.52e-20, - 3.19e-20, - 3.56e-20, - 8.65e-20, - 2.09e-19, - 2.07e-19, - 3.01e-19, - 5.07e-19, - 1.51e-19, - 2.19e-19, - 3.04e-19, - 4.44e-19, - 6.96e-19, - 1.05e-18, - 1.45e-18, - ], - ), - "q": ( - "wvl", - [ - 1.016, - 1.011, - 0.992, - 0.976, - 0.981, - 0.986, - 0.991, - 0.985, - 0.973, - 0.968, - 0.965, - 0.964, - 0.969, - 0.984, - 0.984, - 0.966, - 0.948, - 0.951, - 0.944, - 0.934, - 0.965, - 0.958, - 0.953, - 0.945, - 0.936, - 0.928, - 0.922, - ], - ), - "r": ( - "wvl", + perturb_coeffs: PerturbationCoefficientDataArray = pd.Field( + default=PerturbationCoefficientDataArray( + np.column_stack( [ - 1.25e-18, - 1.53e-18, - 2.28e-18, - 5.19e-18, - 3.62e-18, - 9.28e-18, - 9.99e-18, - 1.29e-17, - 2.03e-17, - 3.31e-17, - 6.92e-17, - 8.23e-17, - 1.15e-16, - 4.81e-16, - 7.44e-16, - 7.11e-16, - 5.29e-16, - 9.72e-16, - 1.22e-15, - 1.16e-15, - 3.16e-15, - 1.51e-14, - 2.71e-14, - 2.65e-14, - 2.94e-14, - 6.85e-14, - 2.60e-13, + [ + 3.48e-22, + 8.88e-21, + 3.22e-20, + 1.67e-20, + 6.29e-21, + 3.10e-21, + 7.45e-22, + 2.16e-22, + 9.28e-23, + 4.58e-23, + 3.26e-23, + 2.70e-23, + 2.25e-23, + 1.36e-23, + 1.85e-23, + 3.05e-23, + 4.08e-23, + 4.14e-23, + 3.81e-23, + 4.23e-23, + 5.81e-23, + 8.20e-23, + 1.13e-22, + 1.22e-22, + 1.09e-22, + 1.20e-22, + 1.62e-22, + ], + [ + 1.229, + 1.167, + 1.149, + 1.169, + 1.193, + 1.210, + 1.245, + 1.277, + 1.299, + 1.319, + 1.330, + 1.338, + 1.345, + 1.359, + 1.354, + 1.345, + 1.340, + 1.341, + 1.344, + 1.344, + 1.338, + 1.331, + 1.325, + 1.324, + 1.328, + 1.327, + 1.321, + ], + [ + 1.02e-19, + 5.84e-20, + 6.21e-20, + 8.08e-20, + 3.40e-20, + 6.05e-20, + 5.43e-20, + 5.58e-20, + 6.65e-20, + 8.53e-20, + 1.53e-19, + 1.22e-19, + 1.29e-19, + 9.99e-20, + 1.32e-19, + 1.57e-18, + 1.45e-18, + 1.70e-18, + 1.25e-18, + 8.14e-19, + 1.55e-18, + 4.81e-18, + 4.72e-18, + 2.09e-18, + 1.16e-18, + 2.01e-18, + 7.52e-18, + ], + [ + 1.089, + 1.109, + 1.119, + 1.123, + 1.151, + 1.145, + 1.153, + 1.158, + 1.160, + 1.159, + 1.149, + 1.158, + 1.160, + 1.170, + 1.167, + 1.111, + 1.115, + 1.115, + 1.125, + 1.137, + 1.124, + 1.100, + 1.102, + 1.124, + 1.140, + 1.130, + 1.101, + ], + [ + 2.98e-22, + 5.40e-22, + 1.91e-21, + 5.70e-21, + 6.57e-21, + 6.95e-21, + 7.25e-21, + 1.19e-20, + 2.46e-20, + 3.64e-20, + 4.96e-20, + 5.91e-20, + 5.52e-20, + 3.19e-20, + 3.56e-20, + 8.65e-20, + 2.09e-19, + 2.07e-19, + 3.01e-19, + 5.07e-19, + 1.51e-19, + 2.19e-19, + 3.04e-19, + 4.44e-19, + 6.96e-19, + 1.05e-18, + 1.45e-18, + ], + [ + 1.016, + 1.011, + 0.992, + 0.976, + 0.981, + 0.986, + 0.991, + 0.985, + 0.973, + 0.968, + 0.965, + 0.964, + 0.969, + 0.984, + 0.984, + 0.966, + 0.948, + 0.951, + 0.944, + 0.934, + 0.965, + 0.958, + 0.953, + 0.945, + 0.936, + 0.928, + 0.922, + ], + [ + 1.25e-18, + 1.53e-18, + 2.28e-18, + 5.19e-18, + 3.62e-18, + 9.28e-18, + 9.99e-18, + 1.29e-17, + 2.03e-17, + 3.31e-17, + 6.92e-17, + 8.23e-17, + 1.15e-16, + 4.81e-16, + 7.44e-16, + 7.11e-16, + 5.29e-16, + 9.72e-16, + 1.22e-15, + 1.16e-15, + 3.16e-15, + 1.51e-14, + 2.71e-14, + 2.65e-14, + 2.94e-14, + 6.85e-14, + 2.60e-13, + ], + [ + 0.835, + 0.838, + 0.841, + 0.832, + 0.849, + 0.834, + 0.839, + 0.838, + 0.833, + 0.826, + 0.812, + 0.812, + 0.807, + 0.776, + 0.769, + 0.774, + 0.783, + 0.772, + 0.769, + 0.772, + 0.750, + 0.716, + 0.704, + 0.706, + 0.705, + 0.686, + 0.656, + ], ], ), - "s": ( - "wvl", - [ - 0.835, - 0.838, - 0.841, - 0.832, - 0.849, - 0.834, - 0.839, - 0.838, - 0.833, - 0.826, - 0.812, - 0.812, - 0.807, - 0.776, - 0.769, - 0.774, - 0.783, - 0.772, - 0.769, - 0.772, - 0.750, - 0.716, - 0.704, - 0.706, - 0.705, - 0.686, - 0.656, - ], - ), - }, - coords={"wvl": np.array([1.3, 1.55] + list(np.arange(2, 14.5, 0.5)))}, + dims=("wvl", "coeff"), + coords={ + "wvl": np.array([1.3, 1.55, *list(np.arange(2, 14.5, 0.5))]), + "coeff": ["a", "b", "c", "d", "p", "q", "r", "s"], + }, + name="perturb_coeffs", + ) ) ref_freq: pd.NonNegativeFloat = pd.Field( - ..., title="Reference Frequency", description="Reference frequency to evaluate perturbation at (Hz).", units=HERTZ, ) - electrons_grid: np.ndarray = pd.Field( - np.concatenate(([0], np.logspace(-6, 22, num=200))), + electrons_grid: ArrayLike = pd.Field( + default=np.concatenate(([0], np.logspace(-6, 22, num=200))), title="Electron concentration grid.", descriptio="The model will be evaluated at these concentration values. Since " "the data at these locations will later be interpolated to determine perturbations " @@ -1531,8 +1522,8 @@ class NedeljkovicSorefMashanovich(AbstractDeltaModel): "i.e., `np.concatenate(([0], np.logspace(-6, 22, num=200)))`.", ) - holes_grid: np.ndarray = pd.Field( - np.concatenate(([0], np.logspace(-6, 22, num=200))), + holes_grid: ArrayLike = pd.Field( + default=np.concatenate(([0], np.logspace(-6, 22, num=200))), title="Hole concentration grid.", descriptio="The model will be evaluated at these concentration values. Since " "the data at these locations will later be interpolated to determine perturbations " @@ -1582,11 +1573,11 @@ def delta_k(self) -> ChargePerturbationType: Ne_mesh, Nh_mesh = np.meshgrid(Ne_range, Nh_range, indexing="ij") # get parameters a, b, c, d - ke_coeff = self._coeffs_at_ref_freq["a"].item() - ke_pow = self._coeffs_at_ref_freq["b"].item() + ke_coeff = self._coeffs_at_ref_freq.sel(coeff="a").item() + ke_pow = self._coeffs_at_ref_freq.sel(coeff="b").item() - kh_coeff = self._coeffs_at_ref_freq["c"].item() - kh_pow = self._coeffs_at_ref_freq["d"].item() + kh_coeff = self._coeffs_at_ref_freq.sel(coeff="c").item() + kh_pow = self._coeffs_at_ref_freq.sel(coeff="d").item() dk_mesh = ke_coeff * Ne_mesh**ke_pow + kh_coeff * Nh_mesh**kh_pow @@ -1597,7 +1588,7 @@ def delta_k(self) -> ChargePerturbationType: dk_mesh = dk_mesh * k_factor # convert t ChargeDataArray - dk_data = ChargeDataArray(dk_mesh, coords=dict(n=Ne_range, p=Nh_range)) + dk_data = ChargeDataArray(dk_mesh, coords={"n": Ne_range, "p": Nh_range}) # create CustomChargePerturbation k_si_charge = CustomChargePerturbation(perturbation_values=dk_data) @@ -1616,16 +1607,16 @@ def delta_n(self) -> ChargePerturbationType: Ne_mesh, Nh_mesh = np.meshgrid(Ne_range, Nh_range, indexing="ij") # get parameters p, q, r, s - ne_coeff = self._coeffs_at_ref_freq["p"].item() - ne_pow = self._coeffs_at_ref_freq["q"].item() + ne_coeff = self._coeffs_at_ref_freq.sel(coeff="p").item() + ne_pow = self._coeffs_at_ref_freq.sel(coeff="q").item() - nh_coeff = self._coeffs_at_ref_freq["r"].item() - nh_pow = self._coeffs_at_ref_freq["s"].item() + nh_coeff = self._coeffs_at_ref_freq.sel(coeff="r").item() + nh_pow = self._coeffs_at_ref_freq.sel(coeff="s").item() dn_mesh = -ne_coeff * Ne_mesh**ne_pow - nh_coeff * Nh_mesh**nh_pow # create ChargeDataArray - dn_data = ChargeDataArray(dn_mesh, coords=dict(n=Ne_range, p=Nh_range)) + dn_data = ChargeDataArray(dn_mesh, coords={"n": Ne_range, "p": Nh_range}) # create CustomChargePerturbation n_si_charge = CustomChargePerturbation(perturbation_values=dn_data) @@ -1687,8 +1678,7 @@ def _check_not_complex(cls, values): if dn_complex or dk_complex: raise DataError( - "Perturbation models 'dn' and 'dk' in 'IndexPerturbation' cannot be " - "complex-valued." + "Perturbation models 'dn' and 'dk' in 'IndexPerturbation' cannot be complex-valued." ) return values diff --git a/tidy3d/components/run_time_spec.py b/tidy3d/components/run_time_spec.py index 5299817609..669ff12e4d 100644 --- a/tidy3d/components/run_time_spec.py +++ b/tidy3d/components/run_time_spec.py @@ -1,4 +1,6 @@ # Defines specifications for how long to run a simulation +from __future__ import annotations + import pydantic.v1 as pd from .base import Tidy3dBaseModel diff --git a/tidy3d/components/scene.py b/tidy3d/components/scene.py index 67c29aa98a..83abbcf330 100644 --- a/tidy3d/components/scene.py +++ b/tidy3d/components/scene.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Literal, Optional, Set, Tuple, Union +from typing import Literal, Optional, Union import autograd.numpy as np @@ -22,10 +22,10 @@ from tidy3d.components.material.types import MultiPhysicsMediumType3D, StructureMediumType from tidy3d.components.tcad.doping import ConstantDoping, GaussianDoping from tidy3d.components.tcad.viz import HEAT_SOURCE_CMAP +from tidy3d.constants import CONDUCTIVITY, THERMAL_CONDUCTIVITY, inf +from tidy3d.exceptions import SetupError, Tidy3dError +from tidy3d.log import log -from ..constants import CONDUCTIVITY, THERMAL_CONDUCTIVITY, inf -from ..exceptions import SetupError, Tidy3dError -from ..log import log from .base import Tidy3dBaseModel, cached_property from .data.utils import ( CustomSpatialDataType, @@ -54,6 +54,7 @@ InterpMethod, LengthUnit, PermittivityComponent, + PriorityMode, Shapely, Size, ) @@ -102,12 +103,24 @@ class Scene(Tidy3dBaseModel): discriminator=TYPE_TAG_STR, ) - structures: Tuple[Structure, ...] = pd.Field( + structures: tuple[Structure, ...] = pd.Field( (), title="Structures", description="Tuple of structures present in scene. " - "Note: Structures defined later in this list override the " - "simulation material properties in regions of spatial overlap.", + "Note: In regions of spatial overlap between structures, " + "material properties are dictated by structure of higher priority. " + "The priority for structure of `priority=None` is set automatically " + "based on `structure_priority_mode`. For structures of equal priority, " + "the structure added later to the structure list takes precedence.", + ) + + structure_priority_mode: PriorityMode = pd.Field( + "equal", + title="Structure Priority Setting", + description="This field only affects structures of `priority=None`. " + "If `equal`, the priority of those structures is set to 0; if `conductor`, " + "the priority of structures made of `LossyMetalMedium` is set to 90, " + "`PECMedium` to 100, and others to 0.", ) plot_length_units: Optional[LengthUnit] = pd.Field( @@ -220,7 +233,7 @@ def box(self) -> Box: return Box(center=self.center, size=self.size) @cached_property - def mediums(self) -> Set[StructureMediumType]: + def mediums(self) -> set[StructureMediumType]: """Returns set of distinct :class:`.AbstractMedium` in scene. Returns @@ -233,7 +246,7 @@ def mediums(self) -> Set[StructureMediumType]: return list(medium_dict.keys()) @cached_property - def medium_map(self) -> Dict[StructureMediumType, pd.NonNegativeInt]: + def medium_map(self) -> dict[StructureMediumType, pd.NonNegativeInt]: """Returns dict mapping medium to index in material. ``medium_map[medium]`` returns unique global index of :class:`.AbstractMedium` in scene. @@ -245,6 +258,17 @@ def medium_map(self) -> Dict[StructureMediumType, pd.NonNegativeInt]: return {medium: index for index, medium in enumerate(self.mediums)} + @cached_property + def sorted_structures(self) -> list[Structure]: + """Returns a list of sorted structures based on their priority.In the sorted list, + latter added structures take higher priority. + + Returns + ------- + List[:class:`.Structure`] + """ + return Structure._sort_structures(self.structures, self.structure_priority_mode) + @cached_property def background_structure(self) -> Structure: """Returns structure representing the background of the :class:`.Scene`.""" @@ -252,14 +276,14 @@ def background_structure(self) -> Structure: return Structure(geometry=geometry, medium=self.medium) @cached_property - def all_structures(self) -> List[Structure]: + def all_structures(self) -> list[Structure]: """List of all structures in the simulation including the background.""" - return [self.background_structure] + list(self.structures) + return [self.background_structure, *self.sorted_structures] @staticmethod def intersecting_media( - test_object: Box, structures: Tuple[Structure, ...] - ) -> Tuple[StructureMediumType, ...]: + test_object: Box, structures: tuple[Structure, ...] + ) -> tuple[StructureMediumType, ...]: """From a given list of structures, returns a list of :class:`.AbstractMedium` associated with those structures that intersect with the ``test_object``, if it is a surface, or its surfaces, if it is a volume. @@ -293,8 +317,8 @@ def intersecting_media( @staticmethod def intersecting_structures( - test_object: Box, structures: Tuple[Structure, ...] - ) -> Tuple[Structure, ...]: + test_object: Box, structures: tuple[Structure, ...] + ) -> tuple[Structure, ...]: """From a given list of structures, returns a list of :class:`.Structure` that intersect with the ``test_object``, if it is a surface, or its surfaces, if it is a volume. @@ -337,12 +361,12 @@ def intersecting_structures( @staticmethod def _get_plot_lims( bounds: Bound, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - ) -> Tuple[Tuple[float, float], Tuple[float, float]]: + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + ) -> tuple[tuple[float, float], tuple[float, float]]: # if no hlim and/or vlim given, the bounds will then be the usual pml bounds axis, _ = Box.parse_xyz_kwargs(x=x, y=y, z=z) _, (hmin, vmin) = Box.pop_axis(bounds[0], axis=axis) @@ -359,18 +383,25 @@ def _get_plot_lims( if vlim[0] > vlim[1]: raise Tidy3dError("Error: 'vmin' > 'vmax'") + if hlim[0] == hlim[1]: + margin = 0.1 * abs(hlim[0]) if hlim[0] != 0 else 0.05 + hlim = (hlim[0] - margin, hlim[1] + margin) + if vlim[0] == vlim[1]: + margin = 0.1 * abs(vlim[0]) if vlim[0] != 0 else 0.05 + vlim = (vlim[0] - margin, vlim[1] + margin) + return hlim, vlim @equal_aspect @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, **patch_kwargs, ) -> Ax: @@ -409,12 +440,12 @@ def plot( @add_ax_if_none def plot_structures( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, fill: bool = True, ) -> Ax: """Plot each of scene's structures on a plane defined by one nonzero x,y,z coordinate. @@ -443,7 +474,7 @@ def plot_structures( """ medium_shapes = self._get_structures_2dbox( - structures=self.to_static().structures, x=x, y=y, z=z, hlim=hlim, vlim=vlim + structures=self.to_static().sorted_structures, x=x, y=y, z=z, hlim=hlim, vlim=vlim ) medium_map = self.medium_map for medium, shape in medium_shapes: @@ -495,9 +526,11 @@ def _get_structure_plot_params( if isinstance(medium, MultiPhysicsMedium): is_pec = medium.optical is not None and medium.optical.is_pec + is_pmc = medium.optical is not None and medium.optical.is_pmc is_time_modulated = medium.optical is not None and medium.optical.is_time_modulated else: is_pec = medium.is_pec + is_pmc = medium.is_pmc is_time_modulated = medium.is_time_modulated if mat_index == 0 or medium == self.medium: @@ -508,6 +541,11 @@ def _get_structure_plot_params( plot_params = plot_params.copy( update={"facecolor": "gold", "edgecolor": "k", "linewidth": 1} ) + elif is_pmc: + # perfect magnetic conductor + plot_params = plot_params.copy( + update={"facecolor": "purple", "edgecolor": "k", "linewidth": 1} + ) elif is_time_modulated: # time modulated medium plot_params = plot_params.copy( @@ -551,11 +589,11 @@ def _add_cbar(vmin: float, vmax: float, label: str, cmap: str, ax: Ax = None) -> def _set_plot_bounds( bounds: Bound, ax: Ax, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Sets the xy limits of the scene at a plane, useful after plotting. @@ -586,13 +624,13 @@ def _set_plot_bounds( def _get_structures_2dbox( self, - structures: List[Structure], - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - ) -> List[Tuple[Medium, Shapely]]: + structures: list[Structure], + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + ) -> list[tuple[Medium, Shapely]]: """Compute list of shapes to plot on 2d box specified by (x_min, x_max), (y_min, y_max). Parameters @@ -647,8 +685,8 @@ def _get_structures_2dbox( @staticmethod def _filter_structures_plane_medium( - structures: List[Structure], plane: Box - ) -> List[Tuple[Medium, Shapely]]: + structures: list[Structure], plane: Box + ) -> list[tuple[Medium, Shapely]]: """Compute list of shapes to plot on plane. Overlaps are removed or merged depending on medium. @@ -672,10 +710,10 @@ def _filter_structures_plane_medium( @staticmethod def _filter_structures_plane( - structures: List[Structure], + structures: list[Structure], plane: Box, - property_list: List, - ) -> List[Tuple[Medium, Shapely]]: + property_list: list, + ) -> list[tuple[Medium, Shapely]]: """Compute list of shapes to plot on plane. Overlaps are removed or merged depending on provided property_list. @@ -703,14 +741,14 @@ def _filter_structures_plane( @add_ax_if_none def plot_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of scene's components on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. @@ -754,17 +792,17 @@ def plot_eps( @add_ax_if_none def plot_structures_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, - eps_lim: Tuple[Union[float, None], Union[float, None]] = (None, None), + eps_lim: tuple[Union[float, None], Union[float, None]] = (None, None), ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, grid: Grid = None, eps_component: Optional[PermittivityComponent] = None, ) -> Ax: @@ -830,17 +868,17 @@ def plot_structures_eps( @add_ax_if_none def plot_structures_property( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, - limits: Tuple[Union[float, None], Union[float, None]] = (None, None), + limits: tuple[Union[float, None], Union[float, None]] = (None, None), ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, grid: Grid = None, property: Literal["eps", "doping", "N_a", "N_d"] = "eps", eps_component: Optional[PermittivityComponent] = None, @@ -889,7 +927,7 @@ def plot_structures_property( The supplied or created matplotlib axes. """ - structures = self.structures + structures = self.sorted_structures # alpha is None just means plot without any transparency if alpha is None: @@ -912,10 +950,10 @@ def plot_structures_property( # for doping background structure could be a non-doping structure # that needs to be rendered if property in ["N_d", "N_a", "doping"]: - structures = [self.background_structure] + list(structures) + structures = [self.background_structure, *list(structures)] medium_shapes = self._filter_structures_plane_medium(structures=structures, plane=plane) else: - structures = [self.background_structure] + list(structures) + structures = [self.background_structure, *list(structures)] medium_shapes = self._get_structures_2dbox( structures=structures, x=x, y=y, z=z, hlim=hlim, vlim=vlim ) @@ -1033,9 +1071,9 @@ def _add_cbar_eps(eps_min: float, eps_max: float, ax: Ax = None, reverse: bool = @staticmethod def _eps_bounds( medium_list: list[Medium], - freq: float = None, + freq: Optional[float] = None, eps_component: Optional[PermittivityComponent] = None, - ) -> Tuple[float, float]: + ) -> tuple[float, float]: """Compute range of (real) permittivity present in the mediums at frequency "freq".""" medium_list = [medium for medium in medium_list if not medium.is_pec] eps_list = [medium._eps_plot(freq, eps_component) for medium in medium_list] @@ -1050,7 +1088,9 @@ def _eps_bounds( eps_max = max(eps_max, mat_epsmax) return eps_min, eps_max - def eps_bounds(self, freq: float = None, eps_component: str = None) -> Tuple[float, float]: + def eps_bounds( + self, freq: Optional[float] = None, eps_component: Optional[str] = None + ) -> tuple[float, float]: """Compute range of (real) permittivity present in the scene at frequency "freq". Parameters @@ -1069,7 +1109,7 @@ def eps_bounds(self, freq: float = None, eps_component: str = None) -> Tuple[flo Minimal and maximal values of relative permittivity in scene. """ - medium_list = [self.medium] + list(self.mediums) + medium_list = [self.medium, *list(self.mediums)] return self._eps_bounds(medium_list=medium_list, freq=freq, eps_component=eps_component) def _pcolormesh_shape_custom_medium_structure_eps( @@ -1148,11 +1188,11 @@ def _pcolormesh_shape_custom_medium_structure_eps( cmap=STRUCTURE_EPS_CMAP, vmin=eps_min, vmax=eps_max, - pcolor_kwargs=dict( - clip_path=(polygon_path(shape), ax.transData), - clip_box=ax.bbox, - alpha=alpha, - ), + pcolor_kwargs={ + "clip_path": (polygon_path(shape), ax.transData), + "clip_box": ax.bbox, + "alpha": alpha, + }, ) return @@ -1242,7 +1282,7 @@ def _get_structure_eps_plot_params( eps_min: float, eps_max: float, reverse: bool = False, - alpha: float = None, + alpha: Optional[float] = None, eps_component: Optional[PermittivityComponent] = None, ) -> PlotParams: """Constructs the plot parameters for a given medium in scene.plot_eps().""" @@ -1259,6 +1299,11 @@ def _get_structure_eps_plot_params( plot_params = plot_params.copy( update={"facecolor": "gold", "edgecolor": "k", "linewidth": 1} ) + elif medium.is_pmc: + # perfect magnetic conductor + plot_params = plot_params.copy( + update={"facecolor": "purple", "edgecolor": "k", "linewidth": 1} + ) elif isinstance(medium, Medium2D): # 2d material plot_params = plot_params.copy(update={"edgecolor": "k", "linewidth": 1}) @@ -1282,7 +1327,7 @@ def _plot_shape_structure_eps( eps_max: float, ax: Ax, reverse: bool = False, - alpha: float = None, + alpha: Optional[float] = None, eps_component: Optional[PermittivityComponent] = None, ) -> Ax: """Plot a structure's cross section shape for a given medium, grayscale for permittivity.""" @@ -1304,15 +1349,15 @@ def _plot_shape_structure_eps( @add_ax_if_none def plot_heat_charge_property( self, - x: float = None, - y: float = None, - z: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, property: str = "heat_conductivity", ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of scebe's components on a plane defined by one nonzero x,y,z coordinate. The thermal conductivity is plotted in grayscale based on its value. @@ -1358,15 +1403,15 @@ def plot_heat_charge_property( @add_ax_if_none def plot_structures_heat_conductivity( self, - x: float = None, - y: float = None, - z: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of scene's structures on a plane defined by one nonzero x,y,z coordinate. The thermal conductivity is plotted in grayscale based on its value. @@ -1423,16 +1468,16 @@ def plot_structures_heat_conductivity( @add_ax_if_none def plot_structures_heat_charge_property( self, - x: float = None, - y: float = None, - z: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, property: str = "heat_conductivity", reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of scene's structures on a plane defined by one nonzero x,y,z coordinate. The thermal conductivity is plotted in grayscale based on its value. @@ -1466,7 +1511,7 @@ def plot_structures_heat_charge_property( The supplied or created matplotlib axes. """ - structures = self.structures + structures = self.sorted_structures # alpha is None just means plot without any transparency if alpha is None: @@ -1482,7 +1527,7 @@ def plot_structures_heat_charge_property( plane = Box(center=center, size=size) medium_shapes = self._filter_structures_plane_medium(structures=structures, plane=plane) else: - structures = [self.background_structure] + list(structures) + structures = [self.background_structure, *list(structures)] medium_shapes = self._get_structures_2dbox( structures=structures, x=x, y=y, z=z, hlim=hlim, vlim=vlim ) @@ -1524,7 +1569,7 @@ def plot_structures_heat_charge_property( ) return ax - def heat_charge_property_bounds(self, property) -> Tuple[float, float]: + def heat_charge_property_bounds(self, property) -> tuple[float, float]: """Compute range of the heat-charge simulation property present in the scene. Returns @@ -1533,7 +1578,7 @@ def heat_charge_property_bounds(self, property) -> Tuple[float, float]: Minimal and maximal values of thermal conductivity in scene. """ - medium_list = [self.medium] + list(self.mediums) + medium_list = [self.medium, *list(self.mediums)] if property == "heat_conductivity": SolidType = (SolidSpec, SolidMedium) medium_list = [ @@ -1553,7 +1598,7 @@ def heat_charge_property_bounds(self, property) -> Tuple[float, float]: cond_max = max(cond_list) return cond_min, cond_max - def heat_conductivity_bounds(self) -> Tuple[float, float]: + def heat_conductivity_bounds(self) -> tuple[float, float]: """Compute range of thermal conductivities present in the scene. Returns @@ -1575,7 +1620,7 @@ def _get_structure_heat_charge_property_plot_params( property_val_min: float, property_val_max: float, reverse: bool = False, - alpha: float = None, + alpha: Optional[float] = None, property: str = "heat_conductivity", ) -> PlotParams: """Constructs the plot parameters for a given medium in @@ -1622,7 +1667,7 @@ def _plot_shape_structure_heat_charge_property( property: str, ax: Ax, reverse: bool = False, - alpha: float = None, + alpha: Optional[float] = None, ) -> Ax: """Plot a structure's cross section shape for a given medium, grayscale for thermal conductivity. @@ -1642,14 +1687,14 @@ def _plot_shape_structure_heat_charge_property( @add_ax_if_none def plot_heat_conductivity( self, - x: float = None, - y: float = None, - z: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ): """Plot each of scebe's components on a plane defined by one nonzero x,y,z coordinate. The thermal conductivity is plotted in grayscale based on its value. @@ -1744,7 +1789,7 @@ def perturbed_mediums_copy( """ scene_dict = self.dict() - structures = self.structures + structures = self.sorted_structures array_dict = { "temperature": temperature, "electron_density": electron_density, @@ -1795,7 +1840,7 @@ def doping_bounds(self): acceptors_lims = [1e50, -1e50] donors_lims = [1e50, -1e50] - for struct in [self.background_structure] + list(self.structures): + for struct in self.all_structures: if isinstance(struct.medium.charge, SemiconductorMedium): electric_spec = struct.medium.charge for doping, limits in zip( diff --git a/tidy3d/components/simulation.py b/tidy3d/components/simulation.py index d89960434a..0bd544bb3e 100644 --- a/tidy3d/components/simulation.py +++ b/tidy3d/components/simulation.py @@ -6,7 +6,7 @@ import pathlib from abc import ABC, abstractmethod from collections import defaultdict -from typing import Dict, List, Optional, Set, Tuple, Union, get_args +from typing import Literal, Optional, Union, get_args import autograd.numpy as np @@ -19,10 +19,12 @@ import pydantic.v1 as pydantic import xarray as xr -from ..constants import C_0, SECOND, fp_eps, inf -from ..exceptions import SetupError, Tidy3dError, Tidy3dImportError, ValidationError -from ..log import log -from ..updater import Updater +from tidy3d.constants import C_0, SECOND, fp_eps, inf +from tidy3d.exceptions import SetupError, Tidy3dError, Tidy3dImportError, ValidationError +from tidy3d.log import log +from tidy3d.packaging import supports_local_subpixel, tidy3d_extras +from tidy3d.updater import Updater + from .base import cached_property, skip_if_fields_missing from .base_sim.simulation import AbstractSimulation from .boundary import ( @@ -108,7 +110,6 @@ CoordinateOptional, FreqBound, InterpMethod, - Literal, PermittivityComponent, Symmetry, annotate_type, @@ -116,8 +117,8 @@ from .validators import ( assert_objects_contained_in_sim_bounds, assert_objects_in_sim_bounds, + named_obj_descr, validate_mode_objects_symmetry, - validate_mode_plane_radius, ) from .viz import ( PlotParams, @@ -137,12 +138,6 @@ except ImportError: gdstk_available = False -try: - gdspy_available = True - import gdspy -except ImportError: - gdspy_available = False - # minimum number of grid points allowed per central wavelength in a medium MIN_GRIDS_PER_WVL = 6.0 @@ -179,7 +174,7 @@ RF_FREQ_WARNING = 300e9 -def validate_boundaries_for_zero_dims(): +def validate_boundaries_for_zero_dims(warn_on_change: bool = True): """Error if absorbing boundaries, bloch boundaries, unmatching pec/pmc, or symmetry is used along a zero dimension.""" @pydantic.validator("boundary_spec", allow_reuse=True, always=True) @@ -198,11 +193,15 @@ def boundaries_for_zero_dims(cls, val, values): num_bloch_bdries = sum(isinstance(bnd, BlochBoundary) for bnd in boundary) if num_absorbing_bdries > 0: - raise SetupError( - f"The simulation has zero size along the {axis} axis, so " - "using a PML or absorbing boundary along that axis is incorrect. " - f"Use either 'Periodic' or 'BlochBoundary' along {axis}." - ) + pbc = Boundary(minus=Periodic(), plus=Periodic()) + val = val.updated_copy(**{axis: pbc}) + if warn_on_change: + log.warning( + f"The simulation has zero size along the {axis} axis, so " + "using a PML or absorbing boundary along that axis is incorrect. " + f"Use either 'Periodic' or 'BlochBoundary' along {axis}. " + "Using 'Periodic' boundary by default." + ) if num_bloch_bdries > 0: raise SetupError( @@ -237,7 +236,7 @@ class AbstractYeeGridSimulation(AbstractSimulation, ABC): Abstract class for a simulation involving electromagnetic fields defined on a Yee grid. """ - lumped_elements: Tuple[LumpedElementType, ...] = pydantic.Field( + lumped_elements: tuple[LumpedElementType, ...] = pydantic.Field( (), title="Lumped Elements", description="Tuple of lumped elements in the simulation. " @@ -398,7 +397,6 @@ def _check_3d_simulation_with_lumped_elements(cls, val, values): @abstractmethod def _validate_auto_grid_wavelength(cls, val, values): """Check that wavelength can be defined if there is auto grid spec.""" - pass def _monitor_num_cells(self, monitor: Monitor) -> int: """Total number of cells included in monitor based on simulation grid.""" @@ -448,15 +446,15 @@ def _subpixel(self) -> SubpixelSpec: @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - source_alpha: float = None, - monitor_alpha: float = None, - lumped_element_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + lumped_element_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, fill_structures: bool = True, **patch_kwargs, ) -> Ax: @@ -529,18 +527,19 @@ def plot( @add_ax_if_none def plot_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, - lumped_element_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + lumped_element_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ax: Ax = None, eps_component: Optional[PermittivityComponent] = None, + eps_lim: tuple[Union[float, None], Union[float, None]] = (None, None), ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. @@ -577,6 +576,8 @@ def plot_eps( Component of the permittivity tensor to plot for anisotropic materials, e.g. ``"xx"``, ``"yy"``, ``"zz"``, ``"xy"``, ``"yz"``, ... Defaults to ``None``, which returns the average of the diagonal values. + eps_lim : Tuple[float, float] = None + Custom limits for eps coloring. Returns ------- @@ -614,6 +615,7 @@ def plot_eps( hlim=hlim, vlim=vlim, eps_component=eps_component, + eps_lim=eps_lim, ) ax = self.plot_sources(ax=ax, x=x, y=y, z=z, hlim=hlim, vlim=vlim, alpha=source_alpha) ax = self.plot_monitors(ax=ax, x=x, y=y, z=z, hlim=hlim, vlim=vlim, alpha=monitor_alpha) @@ -632,17 +634,18 @@ def plot_eps( @add_ax_if_none def plot_structures_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, eps_component: Optional[PermittivityComponent] = None, + eps_lim: tuple[Union[float, None], Union[float, None]] = (None, None), ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. @@ -678,6 +681,8 @@ def plot_structures_eps( Component of the permittivity tensor to plot for anisotropic materials, e.g. ``"xx"``, ``"yy"``, ``"zz"``, ``"xy"``, ``"yz"``, ... Defaults to ``None``, which returns the average of the diagonal values. + eps_lim : Tuple[float, float] = None + Custom limits for eps coloring. Returns ------- @@ -713,17 +718,18 @@ def plot_structures_eps( grid=self.grid, reverse=reverse, eps_component=eps_component, + eps_lim=eps_lim, ) @equal_aspect @add_ax_if_none def plot_pml( self, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's absorbing boundaries @@ -764,7 +770,7 @@ def plot_pml( # candidate for removal in 3.0 @cached_property - def bounds_pml(self) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]: + def bounds_pml(self) -> tuple[tuple[float, float, float], tuple[float, float, float]]: """Simulation bounds including the PML regions.""" log.warning( "'Simulation.bounds_pml' will be removed in Tidy3D 3.0. " @@ -773,7 +779,7 @@ def bounds_pml(self) -> Tuple[Tuple[float, float, float], Tuple[float, float, fl return self.simulation_bounds @cached_property - def simulation_bounds(self) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]: + def simulation_bounds(self) -> tuple[tuple[float, float, float], tuple[float, float, float]]: """Simulation bounds including the PML regions.""" pml_thick = self.pml_thicknesses bounds_in = self.bounds @@ -782,7 +788,7 @@ def simulation_bounds(self) -> Tuple[Tuple[float, float, float], Tuple[float, fl return (bounds_min, bounds_max) - def _make_pml_boxes(self, normal_axis: Axis) -> List[Box]: + def _make_pml_boxes(self, normal_axis: Axis) -> list[Box]: """make a list of Box objects representing the pml to plot on plane.""" pml_boxes = [] pml_thicks = self.pml_thicknesses @@ -815,7 +821,7 @@ def _make_pml_box(self, pml_axis: Axis, pml_height: float, sign: int) -> Box: return pml_box # candidate for removal in 3.0 - def eps_bounds(self, freq: float = None) -> Tuple[float, float]: + def eps_bounds(self, freq: Optional[float] = None) -> tuple[float, float]: """Compute range of (real) permittivity present in the simulation at frequency "freq".""" log.warning( @@ -825,7 +831,7 @@ def eps_bounds(self, freq: float = None) -> Tuple[float, float]: return self.scene.eps_bounds(freq=freq) @cached_property - def pml_thicknesses(self) -> List[Tuple[float, float]]: + def pml_thicknesses(self) -> list[tuple[float, float]]: """Thicknesses (um) of absorbers in all three axes and directions (-, +) Returns @@ -843,7 +849,7 @@ def pml_thicknesses(self) -> List[Tuple[float, float]]: return pml_thicknesses @cached_property - def internal_override_structures(self) -> List[MeshOverrideStructure]: + def internal_override_structures(self) -> list[MeshOverrideStructure]: """Internal mesh override structures. So far, internal override structures all come from `layer_refinement_specs`. Returns @@ -860,7 +866,7 @@ def internal_override_structures(self) -> List[MeshOverrideStructure]: ) @cached_property - def internal_snapping_points(self) -> List[CoordinateOptional]: + def internal_snapping_points(self) -> list[CoordinateOptional]: """Internal snapping points. So far, internal snapping points are generated by `layer_refinement_specs`. Returns @@ -876,12 +882,12 @@ def internal_snapping_points(self) -> List[CoordinateOptional]: @add_ax_if_none def plot_lumped_elements( self, - x: float = None, - y: float = None, - z: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's lumped elements on a plane defined by one @@ -921,12 +927,12 @@ def plot_lumped_elements( @add_ax_if_none def plot_grid( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, override_structures_alpha: float = 1, snapping_points_alpha: float = 1, **kwargs, @@ -988,14 +994,20 @@ def plot_grid( edgecolor=kwargs["colors"], alpha=override_structures_alpha, ), - ] * 2 + ] * 3 plot_params[0] = plot_params[0].include_kwargs(edgecolor=kwargs["colors_internal"]) if self.grid_spec.auto_grid_used: + # Internal and external override structures are visualized with different colors, + # so let's not sort them together. all_override_structures = [ - self.internal_override_structures, - self.grid_spec.external_override_structures, + Structure._sort_structures(structures, self.scene.structure_priority_mode) + for structures in [ + self.internal_override_structures, + self.grid_spec.external_override_structures, + ] ] + for structures, plot_param in zip(all_override_structures, plot_params): for structure in structures: bounds = list(zip(*structure.geometry.bounds)) @@ -1014,7 +1026,12 @@ def plot_grid( # Plot snapping points for points, plot_param in zip( - [self.internal_snapping_points, self.grid_spec.snapping_points], plot_params + [ + self.internal_snapping_points, + self.grid_spec.snapping_points, + self._gap_meshing_snapping_lines, + ], + plot_params, ): for point in points: _, (x_point, y_point) = Geometry.pop_axis(point, axis=axis) @@ -1058,9 +1075,9 @@ def plot_grid( @add_ax_if_none def plot_boundaries( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **kwargs, ) -> Ax: @@ -1188,20 +1205,31 @@ def set_plot_params(boundary_edge, lim, side, thickness): # return plot_sim_3d(self, width=width, height=height) @cached_property - def grid(self) -> Grid: + def _grid_and_snapping_lines(self) -> tuple[Grid, list[CoordinateOptional]]: """FDTD grid spatial locations and information. Returns ------- - :class:`.Grid` - :class:`.Grid` storing the spatial locations relevant to the simulation. + Tuple[:class:`.Grid`, List[CoordinateOptional]] + :class:`.Grid` storing the spatial locations relevant to the simulation + the list of snapping points generated during iterative gap meshing. """ # Add a simulation Box as the first structure structures = [Structure(geometry=self.geometry, medium=self.medium)] structures += self.static_structures - grid = self.grid_spec.make_grid( + # Get boundary types (relevant for gap meshing) + boundary_types = [[None] * 2] * 3 + + for dim, boundary in enumerate(self.boundary_spec.to_list): + for side, edge in enumerate(boundary): + if isinstance(edge, (PECBoundary, PMCBoundary)): + boundary_types[dim][side] = "pec/pmc" + elif isinstance(edge, (Periodic, BlochBoundary)): + boundary_types[dim][side] = "periodic" + + grid, lines = self.grid_spec._make_grid_and_snapping_lines( structures=structures, symmetry=self.symmetry, periodic=self._periodic, @@ -1210,16 +1238,48 @@ def grid(self) -> Grid: lumped_elements=self.lumped_elements, internal_snapping_points=self.internal_snapping_points, internal_override_structures=self.internal_override_structures, + boundary_types=boundary_types, + structure_priority_mode=self.scene.structure_priority_mode, ) + # This would AutoGrid the in-plane directions of the 2D materials + # return self._grid_corrections_2dmaterials(grid) + return grid, lines + + @cached_property + def grid(self) -> Grid: + """FDTD grid spatial locations and information. + + Returns + ------- + :class:`.Grid` + :class:`.Grid` storing the spatial locations relevant to the simulation. + """ + + grid, _ = self._grid_and_snapping_lines + # This would AutoGrid the in-plane directions of the 2D materials # return self._grid_corrections_2dmaterials(grid) return grid + @cached_property + def _gap_meshing_snapping_lines(self) -> list[CoordinateOptional]: + """Snapping points resulted from iterative gap meshing. + + Returns + ------- + List[CoordinateOptional] + List of snapping lines resolving thin gaps and strips. + """ + + _, lines = self._grid_and_snapping_lines + + return lines + @cached_property def static_structures(self) -> list[Structure]: """Structures in simulation with all autograd tracers removed.""" - return [structure.to_static() for structure in self.structures] + return [structure.to_static() for structure in self.scene.sorted_structures] @cached_property def num_cells(self) -> int: @@ -1234,7 +1294,7 @@ def num_cells(self) -> int: return np.prod(self.grid.num_cells, dtype=np.int64) @cached_property - def grid_info(self) -> Dict: + def grid_info(self) -> dict: """Dictionary collecting various properties of the grids in the simulation.""" return self.grid.info @@ -1255,7 +1315,7 @@ def _subgrid(self, span_inds: np.ndarray, grid: Grid = None): return Grid(boundaries=Coords(**boundary_dict)) @cached_property - def _periodic(self) -> Tuple[bool, bool, bool]: + def _periodic(self) -> tuple[bool, bool, bool]: """For each dimension, ``True`` if periodic/Bloch boundaries and ``False`` otherwise. We check on both sides but in practice there should be no cases in which a periodic/Bloch BC is on one side only. This is explicitly validated for Bloch, and implicitly done for @@ -1267,7 +1327,7 @@ def _periodic(self) -> Tuple[bool, bool, bool]: return periodic @cached_property - def num_pml_layers(self) -> List[Tuple[float, float]]: + def num_pml_layers(self) -> list[tuple[float, float]]: """Number of absorbing layers in all three axes and directions (-, +). Returns @@ -1308,7 +1368,9 @@ def _discretize_grid(self, box: Box, grid: Grid, extend: bool = False) -> Grid: span_inds = grid.discretize_inds(box=box, extend=extend) return self._subgrid(span_inds=span_inds, grid=grid) - def _discretize_inds_monitor(self, monitor: Union[Monitor, Box], colocate: bool = None): + def _discretize_inds_monitor( + self, monitor: Union[Monitor, Box], colocate: Optional[bool] = None + ): """Start and stopping indexes for the cells where data needs to be recorded to fully cover a ``monitor``. This is used during the solver run. The final grid on which a monitor data lives is computed in ``discretize_monitor``, with the difference being that 0-sized @@ -1367,7 +1429,7 @@ def epsilon( self, box: Box, coord_key: str = "centers", - freq: float = None, + freq: Optional[float] = None, ) -> xr.DataArray: """Get array of permittivity at volume specified by box and freq. @@ -1404,11 +1466,12 @@ def epsilon( sub_grid = self.discretize(box) return self.epsilon_on_grid(grid=sub_grid, coord_key=coord_key, freq=freq) + @supports_local_subpixel def epsilon_on_grid( self, grid: Grid, coord_key: str = "centers", - freq: float = None, + freq: Optional[float] = None, ) -> xr.DataArray: """Get array of permittivity at a given freq on a given grid. @@ -1448,6 +1511,10 @@ def epsilon_on_grid( "Epsilon calculation may be slow." ) + if tidy3d_extras["use_local_subpixel"]: + subpixel_sim = tidy3d_extras["mod"].SubpixelSimulation.from_simulation(self) + return subpixel_sim.epsilon_on_grid(grid=grid, coord_key=coord_key, freq=freq) + def get_eps(structure: Structure, frequency: float, coords: Coords): """Select the correct epsilon component if field locations are requested.""" if coord_key[0] != "E": @@ -1512,7 +1579,7 @@ def make_eps_data(coords: Coords): coords = grid[coord_key] return make_eps_data(coords) - def _volumetric_structures_grid(self, grid: Grid) -> Tuple[Structure]: + def _volumetric_structures_grid(self, grid: Grid) -> tuple[Structure]: """Generate a tuple of structures wherein any 2D materials are converted to 3D volumetric equivalents, using ``grid`` as the simulation grid.""" @@ -1520,9 +1587,9 @@ def _volumetric_structures_grid(self, grid: Grid) -> Tuple[Structure]: not any(isinstance(medium, Medium2D) for medium in self.scene.mediums) and not self.lumped_elements ): - return self.structures + return self.scene.sorted_structures - def get_dls(geom: Geometry, axis: Axis, num_dls: int) -> List[float]: + def get_dls(geom: Geometry, axis: Axis, num_dls: int) -> list[float]: """Get grid size around the 2D material.""" dls = self._discretize_grid(Box.from_bounds(*geom.bounds), grid=grid).sizes.to_list[ axis @@ -1557,8 +1624,9 @@ def snap_to_grid(geom: Geometry, axis: Axis) -> Geometry: # Convert lumped elements into structures lumped_structures = [] - strict_ineq = 3 * [True] for lumped_element in self.lumped_elements: + strict_ineq = 3 * [False] + strict_ineq[lumped_element.normal_axis] = True if self.geometry.contains(lumped_element.geometry, strict_inequality=strict_ineq): lumped_structures += lumped_element.to_structures(self.grid) @@ -1610,12 +1678,12 @@ def snap_to_grid(geom: Geometry, axis: Axis) -> Geometry: return tuple(new_structures) @cached_property - def volumetric_structures(self) -> Tuple[Structure]: + def volumetric_structures(self) -> tuple[Structure]: """Generate a tuple of structures wherein any 2D materials are converted to 3D volumetric equivalents.""" return self._volumetric_structures_grid(self.grid) - def suggest_mesh_overrides(self, **kwargs) -> List[MeshOverrideStructure]: + def suggest_mesh_overrides(self, **kwargs) -> list[MeshOverrideStructure]: """Generate a :class:`.MeshOverrideStructure` `List` which is automatically generated from structures in the simulation. """ @@ -1632,9 +1700,10 @@ def subsection( region: Box, boundary_spec: BoundarySpec = None, grid_spec: Union[GridSpec, Literal["identical"]] = None, - symmetry: Tuple[Symmetry, Symmetry, Symmetry] = None, - sources: Tuple[SourceType, ...] = None, - monitors: Tuple[MonitorType, ...] = None, + symmetry: Optional[tuple[Symmetry, Symmetry, Symmetry]] = None, + warn_symmetry_expansion: bool = True, + sources: Optional[tuple[SourceType, ...]] = None, + monitors: Optional[tuple[MonitorType, ...]] = None, remove_outside_structures: bool = True, remove_outside_custom_mediums: bool = False, include_pml_cells: bool = False, @@ -1660,6 +1729,8 @@ def subsection( New simulation symmetry. If ``None``, then it is inherited from the original simulation. Note that in this case the size and placement of new simulation domain must be commensurate with the original symmetry. + warn_symmetry_expansion : bool = True + Whether to warn when the subsection is expanded to preserve symmetry. sources : Tuple[SourceType, ...] = None New list of sources. If ``None``, then the sources intersecting the new simulation domain are inherited from the original simulation. @@ -1737,12 +1808,13 @@ def subsection( center = (new_bounds[0][dim] + new_bounds[1][dim]) / 2 if not math.isclose(center, self.center[dim]): - log.warning( - f"The original simulation is symmetric along {'xyz'[dim]} direction. " - "The requested new simulation region does cross the symmetry plane but is " - "not symmetric with respect to it. To preserve correct symmetry, " - "the requested simulation region is expanded symmetrically." - ) + if warn_symmetry_expansion: + log.warning( + f"The original simulation is symmetric along {'xyz'[dim]} direction. " + "The requested new simulation region does cross the symmetry plane but is " + "not symmetric with respect to it. To preserve correct symmetry, " + "the requested simulation region is expanded symmetrically." + ) new_bounds[0][dim] = 2 * self.center[dim] - new_bounds[1][dim] # symmetry and grid spec treatments could change new simulation bounds @@ -1897,6 +1969,10 @@ def subsection( # 2) Assemble the full simulation without validation return new_sim.updated_copy(structures=new_structures, deep=deep_copy, validate=False) + def _invalidate_solver_cache(self) -> None: + """Clear cached attributes that become stale when subpixel changes.""" + self._cached_properties.pop("_mode_solver", None) + class Simulation(AbstractYeeGridSimulation): """ @@ -2055,6 +2131,17 @@ class Simulation(AbstractYeeGridSimulation): gt=0.0, le=1.0, ) + + precision: Literal["hybrid", "double"] = pydantic.Field( + "hybrid", + title="Floating-point Precision", + description="Floating point precision to use in the computations. By default, Tidy3D uses " + "a hybrid approach that offers a good balance of speed and accuracy for almost all " + "simulations. However, for large simulations (or simulations with a long run time), " + "where very high accuracy is needed, the precision can be set to double everywhere. " + "Note that this doubles the FlexCredit cost of the simulation.", + ) + """The Courant-Friedrichs-Lewy (CFL) stability factor :math:`C`, controls time step to spatial step ratio. A physical wave has to propagate slower than the numerical information propagation in a Yee-cell grid. This is because in this spatially-discrete grid, information propagates over 1 spatial step :math:`\\Delta x` @@ -2127,7 +2214,7 @@ class Simulation(AbstractYeeGridSimulation): * `Numerical dispersion in FDTD `_ """ - lumped_elements: Tuple[LumpedElementType, ...] = pydantic.Field( + lumped_elements: tuple[LumpedElementType, ...] = pydantic.Field( (), title="Lumped Elements", description="Tuple of lumped elements in the simulation. ", @@ -2356,7 +2443,7 @@ class Simulation(AbstractYeeGridSimulation): data. If ``None``, the raw field data is returned. If ``None``, the raw field data is returned unnormalized. """ - monitors: Tuple[annotate_type(MonitorType), ...] = pydantic.Field( + monitors: tuple[annotate_type(MonitorType), ...] = pydantic.Field( (), title="Monitors", description="Tuple of monitors in the simulation. " @@ -2372,7 +2459,7 @@ class Simulation(AbstractYeeGridSimulation): All the monitor implementations. """ - sources: Tuple[annotate_type(SourceType), ...] = pydantic.Field( + sources: tuple[annotate_type(SourceType), ...] = pydantic.Field( (), title="Sources", description="Tuple of electric current sources injecting fields into the simulation.", @@ -2424,7 +2511,7 @@ class Simulation(AbstractYeeGridSimulation): Set to ``0`` to disable this feature. """ - structures: Tuple[Structure, ...] = pydantic.Field( + structures: tuple[Structure, ...] = pydantic.Field( (), title="Structures", description="Tuple of structures present in simulation. " @@ -2489,7 +2576,7 @@ class Simulation(AbstractYeeGridSimulation): * `Structures `_ """ - symmetry: Tuple[Symmetry, Symmetry, Symmetry] = pydantic.Field( + symmetry: tuple[Symmetry, Symmetry, Symmetry] = pydantic.Field( (0, 0, 0), title="Symmetries", description="Tuple of integers defining reflection symmetry across a plane " @@ -2604,7 +2691,7 @@ def _validate_auto_grid_wavelength(cls, val, values): _sources_in_bounds = assert_objects_in_sim_bounds("sources", strict_inequality=True) _lumped_elements_in_bounds = assert_objects_contained_in_sim_bounds( - "lumped_elements", error=False, strict_inequality=True + "lumped_elements", error=False, strict_inequality=False, strict_for_zero_size_dim=True ) _mode_sources_symmetries = validate_mode_objects_symmetry("sources") _mode_monitors_symmetries = validate_mode_objects_symmetry("monitors") @@ -2809,7 +2896,7 @@ def tfsf_with_symmetry(cls, val, values): return val @staticmethod - def _get_fixed_angle_sources(sources: Tuple[SourceType, ...]) -> Tuple[SourceType, ...]: + def _get_fixed_angle_sources(sources: tuple[SourceType, ...]) -> tuple[SourceType, ...]: """Get list of plane wave sources with ``FixedAngleSpec``.""" return [ @@ -2890,8 +2977,9 @@ def _validate_2d_geometry_has_2d_medium(cls, val, values): for geom in flatten_groups(structure.geometry): zero_dims = geom.zero_dims if len(zero_dims) > 0: + obj_descr = named_obj_descr(structure, "structures", i) consolidated_logger.warning( - f"Structure at 'structures[{i}]' has geometry with zero size along " + f"Structure: {obj_descr} has geometry with zero size along " f"dimensions {zero_dims}, and with a medium that is not a 'Medium2D'. " "This is probably not correct, since the resulting simulation will " "depend on the details of the numerical grid. Consider either " @@ -2947,10 +3035,11 @@ def _structures_not_close_pml(cls, val, values): with log as consolidated_logger: - def warn(istruct, side): + def warn(structure, istruct, side): """Warning message for a structure too close to PML.""" + obj_descr = named_obj_descr(structure, "structures", istruct) consolidated_logger.warning( - f"Structure at structures[{istruct}] was detected as being less " + f"Structure: {obj_descr} was detected as being less " f"than half of a central wavelength from a PML on side {side}. " "To avoid inaccurate results or divergence, please increase gap between " "any structures and PML or fully extend structure through the pml.", @@ -2973,7 +3062,7 @@ def warn(istruct, side): and struct_val > sim_val and abs(sim_val - struct_val) < lambda0 / 2 ): - warn(istruct, axis + "-min") + warn(structure, istruct, axis + "-min") zipped = zip(["x", "y", "z"], sim_bound_max, struct_bound_max, boundaries) for axis, sim_val, struct_val, boundary in zipped: @@ -2985,7 +3074,7 @@ def warn(istruct, side): and struct_val < sim_val and abs(sim_val - struct_val) < lambda0 / 2 ): - warn(istruct, axis + "-max") + warn(structure, istruct, axis + "-max") return val @@ -3024,9 +3113,8 @@ def _warn_monitor_mediums_frequency_range(cls, val, values): medium_str = "The simulation background medium" custom_loc = ["medium", "frequency_range"] else: - medium_str = ( - f"The medium associated with structures[{medium_index - 1}]" - ) + medium_descr = named_obj_descr(medium, "mediums", medium_index) + medium_str = f"The medium associated with {medium_descr}" custom_loc = [ "structures", medium_index - 1, @@ -3034,10 +3122,11 @@ def _warn_monitor_mediums_frequency_range(cls, val, values): "frequency_range", ] + monitor_descr = named_obj_descr(monitor, "monitors", monitor_index) consolidated_logger.warning( f"{medium_str} has a frequency range: ({sci_fmin_med}, {sci_fmax_med}) " - "(Hz) that does not fully cover the frequencies contained in " - f"monitors[{monitor_index}]. " + "(Hz) that does not fully cover the frequencies contained " + f"in {monitor_descr}." "This can cause inaccuracies in the recorded results.", custom_loc=custom_loc, ) @@ -3121,7 +3210,7 @@ def _projection_monitors_homogeneous(cls, val, values): ) structures = values.get("structures") or [] - total_structures = [structure_bg] + list(structures) + total_structures = [structure_bg, *list(structures)] with log as consolidated_logger: for monitor_ind, monitor in enumerate(val): @@ -3196,9 +3285,9 @@ def _projection_direction(cls, val, values): center = np.array(monitor.center) - np.array(monitor.local_origin) pts = [np.array(i) for i in [x, y, z]] normal_displacement = pts[normal_ind] - center[normal_ind] - if np.any(normal_displacement < 0) and normal_dir == "+": - projecting_backwards = True - elif np.any(normal_displacement > 0) and normal_dir == "-": + if (np.any(normal_displacement < 0) and normal_dir == "+") or ( + np.any(normal_displacement > 0) and normal_dir == "-" + ): projecting_backwards = True if projecting_backwards: @@ -3438,8 +3527,8 @@ def _warn_grid_size_too_small(cls, val, values): freq0 = source.source_time.freq0 for medium_index, medium in enumerate(mediums): - # min wavelength in PEC is meaningless and we'll get divide by inf errors - if medium.is_pec: + # min wavelength in PEC/PMC is meaningless and we'll get divide by inf errors + if medium.is_pec or medium.is_pmc: continue # min wavelength in Medium2D is meaningless if isinstance(medium, Medium2D): @@ -3451,8 +3540,10 @@ def _warn_grid_size_too_small(cls, val, values): for comp, (key, grid_spec) in enumerate( zip("xyz", (val.grid_x, val.grid_y, val.grid_z)) ): - if medium.is_pec or ( - isinstance(medium, AnisotropicMedium) and medium.is_comp_pec(comp) + if ( + medium.is_pec + or medium.is_pmc + or (isinstance(medium, AnisotropicMedium) and medium.is_comp_pec(comp)) ): n_material = 1.0 lambda_min = C_0 / freq0 / n_material @@ -3501,7 +3592,7 @@ def _source_homogeneous_isotropic(cls, val, values): ) structures = values.get("structures") or [] - total_structures = [structure_bg] + list(structures) + total_structures = [structure_bg, *list(structures)] # for each plane wave in the sources list with log as consolidated_logger: @@ -3547,6 +3638,53 @@ def _source_homogeneous_isotropic(cls, val, values): "A fixed angle plane wave can only be injected into a homogeneous isotropic" "dispersionless medium." ) + # check if broadband angled gaussian beam frequency variation is too fast + if ( + isinstance(source, (GaussianBeam, AstigmaticGaussianBeam)) + and np.abs(source.angle_theta) > 0 + and source.num_freqs > 1 + ): + + def radius(waist_radius, waist_distance, k0): + """Gaussian beam radius at a given waist distance and k0.""" + z_r = waist_radius**2 * k0 / 2 + return waist_radius * np.sqrt(1 + (waist_distance / z_r) ** 2) + + # A slanted GaussianBeam will accumulate a phase that's frequency-dependent + # like phi = K f, with the derivative dphi / df = K = 2 * pi * n * r * sin(theta) / c_0. + # Here, we compute the maximum value of this coefficient computed at the waist radius + # and over all frequencies. Then we compare this to the frequency spacing to + # determine whether the frequency dependence is too fast, and issue a warning. + optical_path_length = [] + freqs = source.frequency_grid + for freq in freqs: + n_freq, _ = src_medium.nk_model(frequency=freq) + k0 = 2 * np.pi * n_freq * freq / C_0 + if isinstance(source, GaussianBeam): + rad = radius(source.waist_radius, source.waist_distance, k0) + else: + rad = max( + radius(source.waist_sizes[0], source.waist_distances[0], k0), + radius(source.waist_sizes[1], source.waist_distances[1], k0), + ) + optical_path_length.append(n_freq * rad * np.sin(source.angle_theta)) + # Maximum value of the path length over all freqs + max_path_length = np.max(optical_path_length) + # Maximum value of the phase difference + max_phase_diff = max_path_length * 2 * np.pi * (freqs[-1] - freqs[0]) / C_0 + # Compare this in magnitude to the frequency spacing assuming uniform + # spacing. This is heuristic since in reality we use a Chebyshev grid, + # but it should be a good rule of thumb. Because the Chebyshev interpolation + # is much better than simple interpolation, we don't require << 1, just < 1 + if not max_phase_diff / source.num_freqs < 1: + log.warning( + f"Broadband, angled {source.type} source has a phase dependence " + "with frequency that might be under-resolved by the provided " + "number of frequencies. Consider reducing the source bandwidth, " + "or increasing the 'num_freqs' of the source, and verify the " + "source injection in an empty simulation.", + ) + return val @pydantic.validator("normalize_index", always=True) @@ -3598,8 +3736,7 @@ def _post_init_validators(self) -> None: self._validate_tfsf_aux_sources() self._validate_nonlinear_specs() self._validate_custom_source_time() - self._validate_mode_object_bends() - self._warn_mode_object_pml() + self._validate_mode_objects() self._warn_rf_license() def _warn_rf_license(self): @@ -3636,45 +3773,49 @@ def _warn_rf_license(self): msg += rf_component_breakdown_msg log.warning(msg, log_once=True) - def _warn_mode_object_pml(self) -> None: - """Warn if any mode objects have large pml.""" + def _validate_mode_objects(self) -> None: + """Create a ModeSolver for each mode object in order to validate.""" from .mode.mode_solver import ModeSolver - for imnt, monitor in enumerate(self.monitors): - if isinstance(monitor, AbstractModeMonitor): - warn_str = f"'monitors[{imnt}]'" - ModeSolver._warn_thick_pml( - simulation=self, - plane=monitor.geometry, - mode_spec=monitor.mode_spec, - warn_str=warn_str, - ) - for isrc, source in enumerate(self.sources): - if isinstance(source, ModeSource): - warn_str = f"'sources[{isrc}]'" - ModeSolver._warn_thick_pml( - simulation=self, - plane=source.geometry, - mode_spec=source.mode_spec, - warn_str=warn_str, - ) + def validate_mode_object(mode_obj: Union[ModeSource, AbstractModeMonitor], msg_prefix: str): + # Warn if pml is too thick + ModeSolver._warn_thick_pml( + simulation=self, + plane=mode_obj.geometry, + mode_spec=mode_obj.mode_spec, + msg_prefix=msg_prefix, + ) + # Error if mode plane radius is too small + ModeSolver._validate_mode_plane_radius( + mode_spec=mode_obj.mode_spec, + plane=mode_obj.geometry, + sim_geom=self.geometry, + ) + # Test if structures can be rotated if ``angle_rotation=True`` + theta = mode_obj.mode_spec.angle_theta + if np.abs(theta) > 0 and mode_obj.mode_spec.angle_rotation: + structs_in = Scene.intersecting_structures(mode_obj.geometry, self.structures) + translate_kwargs = dict(zip("xyz", mode_obj.center)) + _, axes = mode_obj.pop_axis([0, 1, 2], mode_obj.size.index(0.0)) + # we just pick one of the in-plane axes to test the roation + rotate_kwargs = {"angle": theta, "axis": axes[1]} + ModeSolver._make_rotated_structures(structs_in, translate_kwargs, rotate_kwargs) - def _validate_mode_object_bends(self) -> None: - """Error if any mode sources or monitors with bends have a radius that is too small.""" for imnt, monitor in enumerate(self.monitors): if isinstance(monitor, AbstractModeMonitor): - validate_mode_plane_radius( - mode_spec=monitor.mode_spec, - plane=monitor.geometry, - msg_prefix=f"Monitor at 'monitors[{imnt}]' ", - ) + try: + validate_mode_object(mode_obj=monitor, msg_prefix=f"'monitors[{imnt}]'") + except Exception as e: + raise SetupError( + f"Monitor at 'monitors[{imnt}]' failed validation: {e!s}" + ) from e + for isrc, source in enumerate(self.sources): if isinstance(source, ModeSource): - validate_mode_plane_radius( - mode_spec=source.mode_spec, - plane=source.geometry, - msg_prefix=f"Source at 'sources[{isrc}]' ", - ) + try: + validate_mode_object(mode_obj=source, msg_prefix=f"'sources[{isrc}]'") + except Exception as e: + raise SetupError(f"Source at 'sources[{isrc}]' failed validation: {e!s}") from e def _validate_custom_source_time(self): """Warn if all simulation times are outside CustomSourceTime definition range.""" @@ -3685,8 +3826,9 @@ def _validate_custom_source_time(self): data_times = source.source_time.data_times mint = np.min(data_times) maxt = np.max(data_times) + obj_descr = named_obj_descr(source, "sources", idx) log.warning( - f"'CustomSourceTime' at 'sources[{idx}]' is defined over a time range " + f"'CustomSourceTime': {obj_descr} is defined over a time range " f"'({mint}, {maxt})' which does not include any of the 'Simulation' " f"times '({0, run_time})'. The envelope will be constant extrapolated " "from the first or last value in the 'CustomSourceTime', which may not " @@ -3716,8 +3858,9 @@ def _validate_no_structures_pml(self) -> None: if not isinstance(bound_edge, Absorber) and (in_pml_plus or in_pml_mnus): warn = True if warn: + obj_descr = named_obj_descr(structure, "structures", i) consolidated_logger.warning( - f"A bound of Simulation.structures[{i}] was detected as being " + f"A bound of {obj_descr} was detected as being " "within the simulation PML. We recommend extending structures to " "infinity or completely outside of the simulation PML to avoid " "unexpected effects when the structures are not translationally " @@ -3835,15 +3978,16 @@ def _validate_nonlinear_specs(self) -> None: if isinstance(monitor, AuxFieldTimeMonitor): for aux_field in monitor.fields: if aux_field not in self.aux_fields: + obj_descr = named_obj_descr(monitor, "monitors", i) log.warning( - f"Monitor at 'monitors[{i}]' stores field '{aux_field}', " + f"Monitor: {obj_descr} stores field '{aux_field}', " "which is not used by any of the nonlinear models present " "in the mediums in the simulation. The resulting data " "will be zero." ) @cached_property - def aux_fields(self) -> List[str]: + def aux_fields(self) -> list[str]: """All aux fields available in the simulation.""" fields = [] for medium in self.scene.mediums: @@ -3948,7 +4092,7 @@ def _validate_monitor_size(self) -> None: def _validate_modes_size(self) -> None: """Warn if mode sources or monitors have a large number of points.""" - def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: List): + def warn_mode_size(monitor: AbstractModeMonitor, msg_header: str, custom_loc: list): """Warn if a mode component has a large number of points.""" num_cells = np.prod(self.discretize_monitor(monitor).num_cells) if num_cells > WARN_MODE_NUM_CELLS: @@ -3987,7 +4131,7 @@ def _validate_num_cells_in_mode_objects(self) -> None: of grid cells in their transverse dimensions.""" def check_num_cells( - mode_object: Tuple[ModeSource, ModeMonitor], normal_axis: Axis, msg_header: str + mode_object: tuple[ModeSource, ModeMonitor], normal_axis: Axis, msg_header: str ): disc_grid = self.discretize(mode_object) _, check_axes = Box.pop_axis([0, 1, 2], axis=normal_axis) @@ -4059,7 +4203,7 @@ def _validate_freq_monitors_freq_range(self) -> None: ) @cached_property - def monitors_data_size(self) -> Dict[str, float]: + def monitors_data_size(self) -> dict[str, float]: """Dictionary mapping monitor names to their estimated storage size in bytes.""" data_size = {} for monitor in self.monitors: @@ -4173,14 +4317,14 @@ def _warn_time_monitors_outside_run_time(self) -> None: """ Autograd adjoint support """ - def with_adjoint_monitors(self, sim_fields_keys: list) -> Simulation: + def _with_adjoint_monitors(self, sim_fields_keys: list) -> Simulation: """Copy of self with adjoint field and permittivity monitors for every traced structure.""" - mnts_fld, mnts_eps = self.make_adjoint_monitors(sim_fields_keys=sim_fields_keys) + mnts_fld, mnts_eps = self._make_adjoint_monitors(sim_fields_keys=sim_fields_keys) monitors = list(self.monitors) + list(mnts_fld) + list(mnts_eps) - return self.copy(update=dict(monitors=monitors)) + return self.copy(update={"monitors": monitors}) - def make_adjoint_monitors(self, sim_fields_keys: list) -> tuple[list, list]: + def _make_adjoint_monitors(self, sim_fields_keys: list) -> tuple[list, list]: """Get lists of field and permittivity monitors for this simulation.""" index_to_keys = defaultdict(list) @@ -4188,7 +4332,7 @@ def make_adjoint_monitors(self, sim_fields_keys: list) -> tuple[list, list]: for _, index, *fields in sim_fields_keys: index_to_keys[index].append(fields) - freqs = self.freqs_adjoint + freqs = self._freqs_adjoint adjoint_monitors_fld = [] adjoint_monitors_eps = [] @@ -4197,7 +4341,7 @@ def make_adjoint_monitors(self, sim_fields_keys: list) -> tuple[list, list]: for i, field_keys in index_to_keys.items(): structure = self.structures[i] - mnt_fld, mnt_eps = structure.make_adjoint_monitors( + mnt_fld, mnt_eps = structure._make_adjoint_monitors( freqs=freqs, index=i, field_keys=field_keys ) @@ -4207,7 +4351,7 @@ def make_adjoint_monitors(self, sim_fields_keys: list) -> tuple[list, list]: return adjoint_monitors_fld, adjoint_monitors_eps @property - def freqs_adjoint(self) -> list[float]: + def _freqs_adjoint(self) -> list[float]: """Unique list of all frequencies. For now should be only one.""" freqs = set() @@ -4262,7 +4406,7 @@ def _run_time(self) -> float: # candidate for removal in 3.0 @cached_property - def mediums(self) -> Set[MediumType]: + def mediums(self) -> set[MediumType]: """Returns set of distinct :class:`.AbstractMedium` in simulation. Returns @@ -4278,7 +4422,7 @@ def mediums(self) -> Set[MediumType]: # candidate for removal in 3.0 @cached_property - def medium_map(self) -> Dict[MediumType, pydantic.NonNegativeInt]: + def medium_map(self) -> dict[MediumType, pydantic.NonNegativeInt]: """Returns dict mapping medium to index in material. ``medium_map[medium]`` returns unique global index of :class:`.AbstractMedium` in simulation. @@ -4307,7 +4451,7 @@ def background_structure(self) -> Structure: return self.scene.background_structure @cached_property - def _fixed_angle_sources(self) -> Tuple[SourceType, ...]: + def _fixed_angle_sources(self) -> tuple[SourceType, ...]: """List of plane wave sources with ``FixedAngleSpec``.""" return self._get_fixed_angle_sources(self.sources) @@ -4319,8 +4463,8 @@ def _is_fixed_angle(self) -> bool: # candidate for removal in 3.0 @staticmethod def intersecting_media( - test_object: Box, structures: Tuple[Structure, ...] - ) -> Tuple[MediumType, ...]: + test_object: Box, structures: tuple[Structure, ...] + ) -> tuple[MediumType, ...]: """From a given list of structures, returns a list of :class:`.AbstractMedium` associated with those structures that intersect with the ``test_object``, if it is a surface, or its surfaces, if it is a volume. @@ -4347,8 +4491,8 @@ def intersecting_media( # candidate for removal in 3.0 @staticmethod def intersecting_structures( - test_object: Box, structures: Tuple[Structure, ...] - ) -> Tuple[Structure, ...]: + test_object: Box, structures: tuple[Structure, ...] + ) -> tuple[Structure, ...]: """From a given list of structures, returns a list of :class:`.Structure` that intersect with the ``test_object``, if it is a surface, or its surfaces, if it is a volume. @@ -4442,15 +4586,15 @@ def _check_bloch_vec( def to_gdstk( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt] + gds_layer_dtype_map: Optional[ + dict[AbstractMedium, tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt]] ] = None, - ) -> List: + ) -> list: """Convert a simulation's planar slice to a .gds type polygon list. Parameters @@ -4489,7 +4633,7 @@ def to_gdstk( clip = gdstk.rectangle(bmin, bmax) polygons = [] - for structure in self.structures: + for structure in self.scene.sorted_structures: gds_layer, gds_dtype = gds_layer_dtype_map.get(structure.medium, (0, 0)) for polygon in structure.to_gdstk( x=x, @@ -4510,82 +4654,23 @@ def to_gdstk( return polygons - def to_gdspy( - self, - x: float = None, - y: float = None, - z: float = None, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt] - ] = None, - ) -> List: - """Convert a simulation's planar slice to a .gds type polygon list. - - Parameters - ---------- - x : float = None - Position of plane in x direction, only one of x,y,z can be specified to define plane. - y : float = None - Position of plane in y direction, only one of x,y,z can be specified to define plane. - z : float = None - Position of plane in z direction, only one of x,y,z can be specified to define plane. - gds_layer_dtype_map : Dict - Dictionary mapping mediums to GDSII layer and data type tuples. - - Return - ------ - List - List of `gdspy.Polygon` and `gdspy.PolygonSet`. - """ - if gds_layer_dtype_map is None: - gds_layer_dtype_map = {} - - axis, _ = self.geometry.parse_xyz_kwargs(x=x, y=y, z=z) - _, bmin = self.pop_axis(self.bounds[0], axis) - _, bmax = self.pop_axis(self.bounds[1], axis) - - _, symmetry = self.pop_axis(self.symmetry, axis) - if symmetry[0] != 0: - bmin = (0, bmin[1]) - if symmetry[1] != 0: - bmin = (bmin[0], 0) - clip = gdspy.Rectangle(bmin, bmax) - - polygons = [] - for structure in self.structures: - gds_layer, gds_dtype = gds_layer_dtype_map.get(structure.medium, (0, 0)) - for polygon in structure.to_gdspy( - x=x, - y=y, - z=z, - gds_layer=gds_layer, - gds_dtype=gds_dtype, - ): - pmin, pmax = polygon.get_bounding_box() - if pmin[0] < bmin[0] or pmin[1] < bmin[1] or pmax[0] > bmax[0] or pmax[1] > bmax[1]: - polygon = gdspy.boolean( - clip, polygon, "and", layer=gds_layer, datatype=gds_dtype - ) - polygons.append(polygon) - return polygons - def to_gds( self, cell, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt] + gds_layer_dtype_map: Optional[ + dict[AbstractMedium, tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt]] ] = None, ) -> None: """Append the simulation structures to a .gds cell. Parameters ---------- - cell : ``gdstk.Cell`` or ``gdspy.Cell`` + cell : ``gdstk.Cell`` Cell object to which the generated polygons are added. x : float = None Position of plane in x direction, only one of x,y,z can be specified to define plane. @@ -4616,34 +4701,23 @@ def to_gds( if len(polygons) > 0: cell.add(*polygons) - elif gdspy_available and isinstance(cell, gdspy.Cell): - polygons = self.to_gdspy(x=x, y=y, z=z, gds_layer_dtype_map=gds_layer_dtype_map) - if len(polygons) > 0: - cell.add(polygons) - elif "gdstk" in cell.__class__ and not gdstk_available: raise Tidy3dImportError( "Module 'gdstk' not found. It is required to export shapes to gdstk cells." ) - elif "gdspy" in cell.__class__ and not gdspy_available: - raise Tidy3dImportError( - "Module 'gdspy' not found. It is required to export shapes to gdspy cells." - ) else: - raise Tidy3dError( - "Argument 'cell' must be an instance of 'gdstk.Cell' or 'gdspy.Cell'." - ) + raise Tidy3dError("Argument 'cell' must be an instance of 'gdstk.Cell'.") def to_gds_file( self, fname: str, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt] + gds_layer_dtype_map: Optional[ + dict[AbstractMedium, tuple[pydantic.NonNegativeInt, pydantic.NonNegativeInt]] ] = None, gds_cell_name: str = "MAIN", ) -> None: @@ -4673,14 +4747,10 @@ def to_gds_file( library = gdstk.Library() reference = gdstk.Reference rotation = np.pi - elif gdspy_available: - library = gdspy.GdsLibrary() - reference = gdspy.CellReference - rotation = 180 else: raise Tidy3dImportError( - "Python modules 'gdspy' and 'gdstk' not found. To export geometries to .gds " - "files, please install one of those those modules." + "Python module 'gdstk' not found. To export geometries to .gds " + "files, please install 'gdstk'." ) cell = library.new_cell(gds_cell_name) @@ -4809,7 +4879,7 @@ def self_structure(self) -> Structure: return self.scene.background_structure @cached_property - def all_structures(self) -> List[Structure]: + def all_structures(self) -> list[Structure]: """List of all structures in the simulation (including the ``Simulation.medium``).""" return self.scene.all_structures @@ -5012,7 +5082,7 @@ def nyquist_step(self) -> int: return nyquist_step @property - def custom_datasets(self) -> List[Dataset]: + def custom_datasets(self) -> list[Dataset]: """List of custom datasets for verification purposes. If the list is not empty, then the simulation needs to be exported to hdf5 to store the data. """ @@ -5034,7 +5104,7 @@ def custom_datasets(self) -> List[Dataset]: ] datasets_geometry = [] - for struct in self.structures: + for struct in self.scene.sorted_structures: for geometry in traverse_geometries(struct.geometry): if isinstance(geometry, TriangleMesh): datasets_geometry += [geometry.mesh_dataset] @@ -5116,10 +5186,10 @@ def perturbed_mediums_copy( "Please select one before calling this function. This can be " "done with, e.g., 'electron_data.sel(voltage=1)'" ) - elif len(data.values.dims) > 1: + if len(data.values.dims) > 1: new_values = IndexedDataArray( np.array(data.values.data).flatten(), - coords=dict(index=data.values.index.data), + coords={"index": data.values.index.data}, ) if isinstance(data, TetrahedralGridDataset): new_carrier_data[carrier] = TetrahedralGridDataset( diff --git a/tidy3d/components/source/base.py b/tidy3d/components/source/base.py index 09472b1f6a..388896fb5b 100644 --- a/tidy3d/components/source/base.py +++ b/tidy3d/components/source/base.py @@ -3,22 +3,23 @@ from __future__ import annotations from abc import ABC -from typing import Tuple +from typing import Optional import pydantic.v1 as pydantic -from ..base import cached_property -from ..base_sim.source import AbstractSource -from ..geometry.base import Box -from ..types import TYPE_TAG_STR, Ax -from ..validators import _assert_min_freq, _warn_unsupported_traced_argument -from ..viz import ( +from tidy3d.components.base import cached_property +from tidy3d.components.base_sim.source import AbstractSource +from tidy3d.components.geometry.base import Box +from tidy3d.components.types import TYPE_TAG_STR, Ax +from tidy3d.components.validators import _assert_min_freq, _warn_unsupported_traced_argument +from tidy3d.components.viz import ( ARROW_ALPHA, ARROW_COLOR_POLARIZATION, ARROW_COLOR_SOURCE, PlotParams, plot_params_source, ) + from .time import SourceTimeType @@ -46,15 +47,15 @@ def geometry(self) -> Box: @cached_property def _injection_axis(self): """Injection axis of the source.""" - return None + return @cached_property - def _dir_vector(self) -> Tuple[float, float, float]: + def _dir_vector(self) -> tuple[float, float, float]: """Returns a vector indicating the source direction for arrow plotting, if not None.""" return None @cached_property - def _pol_vector(self) -> Tuple[float, float, float]: + def _pol_vector(self) -> tuple[float, float, float]: """Returns a vector indicating the source polarization for arrow plotting, if not None.""" return None @@ -69,9 +70,9 @@ def _freqs_lower_bound(cls, val): def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **patch_kwargs, ) -> Ax: diff --git a/tidy3d/components/source/current.py b/tidy3d/components/source/current.py index 4035b1fbcc..a768a94e59 100644 --- a/tidy3d/components/source/current.py +++ b/tidy3d/components/source/current.py @@ -3,18 +3,21 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Tuple +from math import cos, isclose, sin +from typing import Optional import pydantic.v1 as pydantic from typing_extensions import Literal -from ...constants import MICROMETER -from ..base import cached_property -from ..data.dataset import FieldDataset -from ..data.validators import validate_can_interpolate, validate_no_nans -from ..types import Polarization -from ..validators import assert_single_freq_in_range, warn_if_dataset_none +from tidy3d.components.base import cached_property +from tidy3d.components.data.dataset import FieldDataset +from tidy3d.components.data.validators import validate_can_interpolate, validate_no_nans +from tidy3d.components.types import Polarization +from tidy3d.components.validators import assert_single_freq_in_range, warn_if_dataset_none +from tidy3d.constants import MICROMETER + from .base import Source +from .time import SourceTimeType class CurrentSource(Source, ABC): @@ -27,7 +30,7 @@ class CurrentSource(Source, ABC): ) @cached_property - def _pol_vector(self) -> Tuple[float, float, float]: + def _pol_vector(self) -> tuple[float, float, float]: """Returns a vector indicating the source polarization for arrow plotting, if not None.""" component = self.polarization[-1] # 'x' 'y' or 'z' pol_axis = "xyz".index(component) @@ -99,13 +102,69 @@ class PointDipole(CurrentSource, ReverseInterpolatedSource): * `Adjoint optimization of quantum emitter light extraction to an integrated waveguide <../../notebooks/AdjointPlugin12LightExtractor.html>`_ """ - size: Tuple[Literal[0], Literal[0], Literal[0]] = pydantic.Field( + size: tuple[Literal[0], Literal[0], Literal[0]] = pydantic.Field( (0, 0, 0), title="Size", description="Size in x, y, and z directions, constrained to ``(0, 0, 0)``.", units=MICROMETER, ) + @classmethod + def sources_from_angles( + cls, + source_time: SourceTimeType, + angle_theta: float, + angle_phi: float, + component: Literal["electric", "magnetic"] = "electric", + **kwargs, + ) -> list[PointDipole]: + """Returns a list of `PointDipole` objects used to emulate a single dipole polarized in an arbitrary direction. The direction is specificed using a polar and azimuthal angle. + + Parameters + ---------- + source_time: :class:`.SourceTime` + Specification of the source time-dependence. + angle_theta : float + Polar angle w.r.t. the z-axis. + angle_phi : float + Azimuth angle around the z-axis. + component : Literal["electric", "magnetic"] = "electric" + The type of polarization. + kwargs : dict + Keyword arguments passed to ``PointDipole()``, excluding ``source_time`` and ``polarization`` + + Returns + ------- + list[PointDipole] + A list of ``PointDipole`` objects that emulate a single dipole with an arbitrary direction of polarization. + """ + if not (component == "electric" or component == "magnetic"): + raise ValueError('Component must be "electric" or "magnetic"') + + dipoles: list[PointDipole] = [] + polarizations = ["Ex", "Ey", "Ez"] if component == "electric" else ["Hx", "Hy", "Hz"] + + multipliers = [ + sin(angle_theta) * cos(angle_phi), + sin(angle_theta) * sin(angle_phi), + cos(angle_theta), + ] + + for polarization, mult in zip(polarizations, multipliers): + if not isclose(mult, 0.0, rel_tol=0.0, abs_tol=1e-9): + modulated_source_time = source_time.updated_copy( + amplitude=source_time.amplitude * mult + ) + dipoles.append( + cls( + source_time=modulated_source_time, + polarization=polarization, + **kwargs, + ) + ) + + return dipoles + class CustomCurrentSource(ReverseInterpolatedSource): """Implements a source corresponding to an input dataset containing ``E`` and ``H`` fields. diff --git a/tidy3d/components/source/field.py b/tidy3d/components/source/field.py index 60e172d76d..a67bf019e9 100644 --- a/tidy3d/components/source/field.py +++ b/tidy3d/components/source/field.py @@ -3,37 +3,30 @@ from __future__ import annotations from abc import ABC -from typing import Optional, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pydantic -from ...constants import GLANCING_CUTOFF, MICROMETER, RADIAN, inf -from ...exceptions import SetupError -from ...log import log -from ..base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ..data.dataset import FieldDataset -from ..data.validators import validate_can_interpolate, validate_no_nans -from ..mode_spec import ModeSpec -from ..types import ( - TYPE_TAG_STR, - Ax, - Axis, - Coordinate, - Direction, -) -from ..validators import ( +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.data.dataset import FieldDataset +from tidy3d.components.data.validators import validate_can_interpolate, validate_no_nans +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.types import TYPE_TAG_STR, Ax, Axis, Coordinate, Direction +from tidy3d.components.validators import ( assert_plane, assert_single_freq_in_range, assert_volumetric, warn_if_dataset_none, ) +from tidy3d.constants import GLANCING_CUTOFF, MICROMETER, RADIAN, inf +from tidy3d.exceptions import SetupError +from tidy3d.log import log + from .base import Source # width of Chebyshev grid used for broadband sources (in units of pulse width) CHEB_GRID_WIDTH = 1.5 -# Number of frequencies in a broadband source above which to issue a warning -WARN_NUM_FREQS = 20 # For broadband plane waves with constan in-plane k, the Chebyshev grid is truncated at # ``CRITICAL_FREQUENCY_FACTOR * f_crit``, where ``f_crit`` is the critical frequency # (oblique propagation). @@ -83,7 +76,7 @@ class DirectionalSource(FieldSource, ABC): ) @cached_property - def _dir_vector(self) -> Tuple[float, float, float]: + def _dir_vector(self) -> tuple[float, float, float]: """Returns a vector indicating the source direction for arrow plotting, if not None.""" if self._injection_axis is None: return None @@ -95,14 +88,14 @@ def _dir_vector(self) -> Tuple[float, float, float]: class BroadbandSource(Source, ABC): """A source with frequency dependent field distributions.""" - # Default as for analytic beam sources; overwrriten for ModeSource below num_freqs: int = pydantic.Field( - 3, + 1, title="Number of Frequency Points", description="Number of points used to approximate the frequency dependence of the injected " - "field. Default is 3, which should cover even very broadband sources. For simulations " - "which are not very broadband and the source is very large (e.g. metalens simulations), " - "decreasing the value to 1 may lead to a speed up in the preprocessing.", + "field. A Chebyshev interpolation is used, thus, only a small number of points is " + "typically sufficient to obtain converged results. Note that larger values of 'num_freqs' " + "could spread out the source time signal and introduce numerical noise, or prevent timely " + "field decay.", ge=1, le=20, ) @@ -121,23 +114,6 @@ def _chebyshev_freq_grid(self, freq_min, freq_max): cheb_points = np.cos(np.pi * np.flip(uni_points)) return freq_avg + freq_diff * cheb_points - @pydantic.validator("num_freqs", always=True, allow_reuse=True) - def _warn_if_large_number_of_freqs(cls, val): - """Warn if a large number of frequency points is requested.""" - - if val is None: - return val - - if val >= WARN_NUM_FREQS: - log.warning( - f"A large number ({val}) of frequency points is used in a broadband source. " - "This can lead to solver slow-down and increased cost, and even introduce " - "numerical noise. This may become a hard limit in future Tidy3D versions.", - custom_loc=["num_freqs"], - ) - - return val - """ Source current profiles determined by user-supplied data on a plane.""" @@ -322,7 +298,7 @@ def glancing_incidence(cls, val): return val @cached_property - def _dir_vector(self) -> Tuple[float, float, float]: + def _dir_vector(self) -> tuple[float, float, float]: """Source direction normal vector in cartesian coordinates.""" # Propagation vector assuming propagation along z @@ -335,7 +311,7 @@ def _dir_vector(self) -> Tuple[float, float, float]: return self.unpop_axis(dz, (dx, dy), axis=self._injection_axis) @cached_property - def _pol_vector(self) -> Tuple[float, float, float]: + def _pol_vector(self) -> tuple[float, float, float]: """Source polarization normal vector in cartesian coordinates.""" # Polarization vector assuming propagation along z @@ -427,16 +403,6 @@ class ModeSource(DirectionalSource, PlanarSource, BroadbandSource): "``num_modes`` in the solver will be set to ``mode_index + 1``.", ) - num_freqs: int = pydantic.Field( - 1, - title="Number of Frequency Points", - description="Number of points used to approximate the frequency dependence of injected " - "field. A Chebyshev interpolation is used, thus, only a small number of points, i.e., less " - "than 20, is typically sufficient to obtain converged results.", - ge=1, - le=99, - ) - @cached_property def angle_theta(self): """Polar angle of propagation.""" @@ -448,7 +414,7 @@ def angle_phi(self): return self.mode_spec.angle_phi @cached_property - def _dir_vector(self) -> Tuple[float, float, float]: + def _dir_vector(self) -> tuple[float, float, float]: """Source direction normal vector in cartesian coordinates.""" radius = 1.0 if self.direction == "+" else -1.0 dx = radius * np.cos(self.angle_phi) * np.sin(self.angle_theta) @@ -520,6 +486,17 @@ class PlaneWave(AngledFieldSource, PlanarSource, BroadbandSource): discriminator=TYPE_TAG_STR, ) + num_freqs: int = pydantic.Field( + 3, + title="Number of Frequency Points", + description="Number of points used to approximate the frequency dependence of the injected " + "field. Default is 3, which should cover even very broadband plane waves. For simulations " + "which are not very broadband and the source is very large (e.g. metalens simulations), " + "decreasing the value to 1 may lead to a speed up in the preprocessing.", + ge=1, + le=20, + ) + @cached_property def _is_fixed_angle(self) -> bool: """Whether the plane wave is at a fixed non-zero angle.""" @@ -599,6 +576,18 @@ class GaussianBeam(AngledFieldSource, PlanarSource, BroadbandSource): units=MICROMETER, ) + num_freqs: int = pydantic.Field( + 1, + title="Number of Frequency Points", + description="Number of points used to approximate the frequency dependence of the injected " + "field. For broadband, angled Gaussian beams it is advisable to check the beam propagation " + "in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. " + "Note that larger values of 'num_freqs' could spread out the source time signal and " + "introduce numerical noise, or prevent timely field decay.", + ge=1, + le=20, + ) + class AstigmaticGaussianBeam(AngledFieldSource, PlanarSource, BroadbandSource): """The simple astigmatic Gaussian distribution allows @@ -628,14 +617,14 @@ class AstigmaticGaussianBeam(AngledFieldSource, PlanarSource, BroadbandSource): ... waist_distances = (3.0, 4.0)) """ - waist_sizes: Tuple[pydantic.PositiveFloat, pydantic.PositiveFloat] = pydantic.Field( + waist_sizes: tuple[pydantic.PositiveFloat, pydantic.PositiveFloat] = pydantic.Field( (1.0, 1.0), title="Waist sizes", description="Size of the beam at the waist in the local x and y directions.", units=MICROMETER, ) - waist_distances: Tuple[float, float] = pydantic.Field( + waist_distances: tuple[float, float] = pydantic.Field( (0.0, 0.0), title="Waist distances", description="Distance to the beam waist along the propagation direction " @@ -647,6 +636,18 @@ class AstigmaticGaussianBeam(AngledFieldSource, PlanarSource, BroadbandSource): units=MICROMETER, ) + num_freqs: int = pydantic.Field( + 1, + title="Number of Frequency Points", + description="Number of points used to approximate the frequency dependence of the injected " + "field. For broadband, angled Gaussian beams it is advisable to check the beam propagation " + "in an empty simulation to ensure there are no injection artifacts when 'num_freqs' > 1. " + "Note that larger values of 'num_freqs' could spread out the source time signal and " + "introduce numerical noise, or prevent timely field decay.", + ge=1, + le=20, + ) + class TFSF(AngledFieldSource, VolumeSource, BroadbandSource): """Total-field scattered-field (TFSF) source that can inject a plane wave in a finite region. @@ -705,9 +706,9 @@ def injection_plane_center(self) -> Coordinate: def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **patch_kwargs, ) -> Ax: diff --git a/tidy3d/components/source/freq_range.py b/tidy3d/components/source/freq_range.py new file mode 100644 index 0000000000..231fded64b --- /dev/null +++ b/tidy3d/components/source/freq_range.py @@ -0,0 +1,228 @@ +"""Utility class ``FreqRange`` for frequency and wavelength handling.""" + +from __future__ import annotations + +import numpy as np +import pydantic.v1 as pydantic +from numpy.typing import NDArray + +from tidy3d import constants as td_const +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.source.time import GaussianPulse + + +class FreqRange(Tidy3dBaseModel): + """ + Convenience class for handling frequency/wavelength conversion; it simplifies specification + of frequency ranges and sample points for sources and monitors. + + Notes + ----- + Depending on the context the user can define desired frequency range by specifying: + - central frequency ``freq0`` and frequency bandwidth ``fwidth``; + - frequency interval [``fmin``,``fmax``]; + - central wavelength ``wvl0`` and wavelength range ``wvl_width``; + - wavelength interval [``wvl_min``, ``wvl_max``]. + + Example + ------- + >>> import tidy3d as td + >>> freq0 = 1e12 + >>> fwidth = 1e11 + >>> freq_range = td.FreqRange(freq0=freq0, fwidth=fwidth) + >>> central_freq = freq_range.freqs(num_points=1) + >>> freqs = freq_range.freqs(num_points=11) + >>> source = freq_range.to_gaussian_pulse() + """ + + freq0: pydantic.PositiveFloat = pydantic.Field( + ..., + title="Central frequency", + description="Real-valued positive central frequency.", + units="Hz", + ) + + fwidth: pydantic.PositiveFloat = pydantic.Field( + ..., + title="Frequency bandwidth", + description="Real-valued positive width of the frequency range (bandwidth).", + units="Hz", + ) + + @property + def fmin(self) -> float: + """Infer lowest frequency ``fmin`` from central frequency ``freq0`` and bandwidth ``fwidth``.""" + return self.freq0 - self.fwidth + + @property + def fmax(self) -> float: + """Infer highest frequency ``fmax`` from central frequency ``freq0`` and bandwidth ``fwidth``.""" + return self.freq0 + self.fwidth + + @property + def lda0(self) -> float: + """Get central wavelength from central frequency and bandwidth.""" + lmin = td_const.C_0 / (self.freq0 + self.fwidth) + lmax = td_const.C_0 / (self.freq0 - self.fwidth) + return 0.5 * (lmin + lmax) + + @classmethod + def from_freq_interval(cls, fmin: float, fmax: float) -> FreqRange: + """ + method ``from_freq_interval()`` creates instance of class ``FreqRange`` from frequency interval + defined by arguments ``fmin`` and ``fmax``. + + NB: central frequency never corresponds to central wavelength! + ``freq0 = (fmin + fmax) / 2`` implies that ``lda0 != (lda_min + lda_max) / 2`` and vise-versa. + + Parameters + ---------- + fmin : float + Lower bound of frequency of interest. + fmax : float + Upper bound of frequency of interest. + + Returns + ------- + FreqRange + An instance of ``FreqRange`` defined by frequency interval [``fmin``, ``fmax``]. + """ + + # extract frequency-related info + freq0 = 0.5 * (fmax + fmin) # extract central freq + fwidth = 0.5 * (fmax - fmin) # extract bandwidth + return cls(freq0=freq0, fwidth=fwidth) + + @classmethod + def from_wavelength(cls, wvl0: float, wvl_width: float) -> FreqRange: + """ + method ``from_wavelength()`` updated instance of class ``FreqRange`` by reassigning new + frequency- and wavelength-related parameters. + + NB: central frequency never corresponds to central wavelength! + ``lda0 = (lda_min + lda_max) / 2`` implies that ``freq0 != (fmin + fmax) / 2`` and vise versa. + + Parameters + ---------- + wvl0 : float + Real-valued central wavelength. + wvl_width : float + Real-valued wavelength range. + + Returns + ------- + FreqRange + An instance of ``FreqRange`` defined by central wavelength ``wvl0`` and wavelength range ``wvl_width``. + """ + + # calculate lowest and highest frequencies + fmin = td_const.C_0 / (wvl0 + wvl_width) + fmax = td_const.C_0 / (wvl0 - wvl_width) + + return cls.from_freq_interval(fmin=fmin, fmax=fmax) + + @classmethod + def from_wvl_interval(cls, wvl_min: float, wvl_max: float) -> FreqRange: + """ + method ``from_wvl_interval()`` updated instance of class ``FreqRange`` by reassigning new + frequency- and wavelength-related parameters. + + NB: central frequency never corresponds to central wavelength! + ``lda0 = (lda_min + lda_max) / 2`` implies that ``freq0 != (fmin + fmax) / 2``. + + Parameters + ---------- + wvl_min : float + The lowest wavelength of interest. + wvl_max : float + The longest wavelength of interest. + + Returns + ------- + FreqRange + An instance of ``FreqRange`` defined by the wavelength interval [``wvl_min``, ``wvl_max``]. + """ + + # convert wavelength intervals to frequency interval + fmax = td_const.C_0 / wvl_min + fmin = td_const.C_0 / wvl_max + + return cls.from_freq_interval(fmin=fmin, fmax=fmax) + + def freqs(self, num_points: int) -> NDArray[np.float64]: + """ + method ``freqs()`` returns a numpy array of ``num_point`` frequencies uniformly + sampled from the specified frequency range; + if ``num_points == 1`` method returns the central frequency ``freq0``. + + Parameters + ---------- + num_points : int + Number of frequency points in a frequency range of interest. + + Returns + ------- + np.ndarray + a numpy array of uniformly distributed frequency samples in a frequency range of interest. + """ + + if num_points == 1: # return central frequency + return np.array([self.freq0]) + else: + # calculate frequency points and corresponding wavelengths + return np.linspace(self.fmin, self.fmax, num_points) + + def ldas(self, num_points: int) -> NDArray[np.float64]: + """ + method ``ldas()`` returns a numpy array of ``num_points`` wavelengths uniformly + sampled from the range of wavelengths; + if ``num_points == 1`` the method returns central wavelength ``lda0``. + + Parameters + ---------- + num_points : int + Number of wavelength points in a range of wavelengths of interest. + + Returns + ------- + np.ndarray + a numpy array of uniformly distributed wavelength samples in ascending order. + """ + if num_points == 1: # return central wavelength + return np.array([self.lda0]) + else: + # define shortest and longest wavelengths + lmin = td_const.C_0 / self.fmax + lmax = td_const.C_0 / self.fmin + + # generate array of wavelengths (in ascending order) + return np.linspace(lmin, lmax, num_points) + + def to_gaussian_pulse(self, **kwargs) -> GaussianPulse: + """ + method ``to_gaussian_pulse()`` returns instance of class ``GaussianPulse`` + with frequency-specific parameters defined in ``FreqRange``. + + Parameters + ---------- + kwargs : dict + Keyword arguments passed to ``GaussianPulse()``, excluding ``freq0`` & ``fwidth``. + + Returns + ------- + GaussianPulse + A ``GaussianPulse`` that maximizes its amplitude in the frequency range [``fmin``, ``fmax``]. + """ + + duplicate_keys = {"fmin", "fmax"} & kwargs.keys() + if duplicate_keys: + is_plural = len(duplicate_keys) > 1 + keys_str = ", ".join(f"'{key}'" for key in sorted(duplicate_keys, reverse=True)) + raise ValueError( + f"Keyword argument{'s' if is_plural else ''} {keys_str} " + f"conflict{'' if is_plural else 's'} with values already set in the 'FreqRange' object. " + f"Please exclude {'them' if is_plural else 'it'} from the 'to_gaussian_pulse()' call." + ) + + # create an instance of GaussianPulse class with defined frequency params + return GaussianPulse.from_frequency_range(fmin=self.fmin, fmax=self.fmax, **kwargs) diff --git a/tidy3d/components/source/time.py b/tidy3d/components/source/time.py index d66ac9afec..3c0b6b56e9 100644 --- a/tidy3d/components/source/time.py +++ b/tidy3d/components/source/time.py @@ -8,21 +8,15 @@ import numpy as np import pydantic.v1 as pydantic -from ...constants import HERTZ -from ...exceptions import ValidationError -from ..data.data_array import TimeDataArray -from ..data.dataset import TimeDataset -from ..data.validators import validate_no_nans -from ..time import AbstractTimeDependence -from ..types import ( - ArrayComplex1D, - ArrayFloat1D, - Ax, - FreqBound, - PlotVal, -) -from ..validators import warn_if_dataset_none -from ..viz import add_ax_if_none +from tidy3d.components.data.data_array import TimeDataArray +from tidy3d.components.data.dataset import TimeDataset +from tidy3d.components.data.validators import validate_no_nans +from tidy3d.components.time import AbstractTimeDependence +from tidy3d.components.types import ArrayComplex1D, ArrayFloat1D, Ax, FreqBound, PlotVal +from tidy3d.components.validators import warn_if_dataset_none +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import HERTZ +from tidy3d.exceptions import ValidationError # how many units of ``twidth`` from the ``offset`` until a gaussian pulse is considered "off" END_TIME_FACTOR_GAUSSIAN = 10 @@ -355,7 +349,7 @@ def from_values( """ times = np.arange(len(values)) * dt - source_time_dataarray = TimeDataArray(values, coords=dict(t=times)) + source_time_dataarray = TimeDataArray(values, coords={"t": times}) source_time_dataset = TimeDataset(values=source_time_dataarray) return CustomSourceTime( freq0=freq0, diff --git a/tidy3d/components/spice/analysis/dc.py b/tidy3d/components/spice/analysis/dc.py index 7f6c275602..e9e1e2aca5 100644 --- a/tidy3d/components/spice/analysis/dc.py +++ b/tidy3d/components/spice/analysis/dc.py @@ -2,11 +2,12 @@ This class defines standard SPICE electrical_analysis types (electrical simulations configurations). """ +from __future__ import annotations + import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel - -from ....constants import KELVIN +from tidy3d.constants import KELVIN class ChargeToleranceSpec(Tidy3dBaseModel): diff --git a/tidy3d/components/spice/sources/dc.py b/tidy3d/components/spice/sources/dc.py index 7c560ff165..e527468795 100644 --- a/tidy3d/components/spice/sources/dc.py +++ b/tidy3d/components/spice/sources/dc.py @@ -19,12 +19,16 @@ """ -from typing import Optional, Union +from __future__ import annotations + +from typing import Literal, Optional import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.types import ArrayFloat1D from tidy3d.constants import AMP, VOLT +from tidy3d.constants import inf as td_inf class DCVoltageSource(Tidy3dBaseModel): @@ -45,11 +49,23 @@ class DCVoltageSource(Tidy3dBaseModel): """ name: Optional[str] - voltage: Union[pd.FiniteFloat, list[pd.FiniteFloat]] = pd.Field( + voltage: ArrayFloat1D = pd.Field( + ..., title="Voltage", description="DC voltage usually used as source in 'VoltageBC' boundary conditions.", + units=VOLT, ) - units: str = VOLT + + # TODO: This should have always been in the field above but was introduced wrongly as a + # standalone field. Keeping for compatibility, remove in 3.0. + units: Literal[VOLT] = VOLT + + @pd.validator("voltage") + def check_voltage(cls, val): + for v in val: + if v == td_inf: + raise ValueError(f"Voltages must be finite. Currently voltage={val}.") + return val class DCCurrentSource(Tidy3dBaseModel): @@ -66,5 +82,9 @@ class DCCurrentSource(Tidy3dBaseModel): current: pd.FiniteFloat = pd.Field( title="Current", description="DC current usually used as source in 'CurrentBC' boundary conditions.", + units=AMP, ) - units: str = AMP + + # TODO: This should have always been in the field above but was introduced wrongly as a + # standalone field. Keeping for compatibility, remove in 3.0. + units: Literal[AMP] = AMP diff --git a/tidy3d/components/spice/sources/types.py b/tidy3d/components/spice/sources/types.py index 653f48958f..352f8878c1 100644 --- a/tidy3d/components/spice/sources/types.py +++ b/tidy3d/components/spice/sources/types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Union from .dc import DCCurrentSource, DCVoltageSource diff --git a/tidy3d/components/spice/types.py b/tidy3d/components/spice/types.py index 42336397fa..486bd0e734 100644 --- a/tidy3d/components/spice/types.py +++ b/tidy3d/components/spice/types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Union from tidy3d.components.spice.analysis.dc import IsothermalSteadyChargeDCAnalysis diff --git a/tidy3d/components/structure.py b/tidy3d/components/structure.py index 9cf8724dd8..e7168180c5 100644 --- a/tidy3d/components/structure.py +++ b/tidy3d/components/structure.py @@ -4,29 +4,34 @@ import pathlib from collections import defaultdict -from typing import Optional, Tuple, Union +from functools import cmp_to_key +from typing import Optional, Union import autograd.numpy as anp import numpy as np import pydantic.v1 as pydantic -from ..constants import MICROMETER -from ..exceptions import SetupError, Tidy3dError, Tidy3dImportError -from ..log import log +from tidy3d.components.autograd.constants import ( + AUTOGRAD_MONITOR_INTERVAL_SPACE_CUSTOM, + AUTOGRAD_MONITOR_INTERVAL_SPACE_POLY, +) +from tidy3d.constants import MICROMETER +from tidy3d.exceptions import SetupError, Tidy3dImportError +from tidy3d.log import log + from .autograd.derivative_utils import DerivativeInfo from .autograd.types import AutogradFieldMap from .autograd.types import Box as AutogradBox -from .autograd.utils import get_static +from .autograd.utils import contains, get_static from .base import Tidy3dBaseModel, skip_if_fields_missing from .data.data_array import ScalarFieldDataArray from .geometry.base import Box, Geometry -from .geometry.polyslab import PolySlab from .geometry.utils import GeometryType, validate_no_transformed_polyslabs from .grid.grid import Coords from .material.types import StructureMediumType -from .medium import AbstractCustomMedium, CustomMedium, Medium, Medium2D +from .medium import AbstractCustomMedium, CustomMedium, LossyMetalMedium, Medium, Medium2D from .monitor import FieldMonitor, PermittivityMonitor -from .types import TYPE_TAG_STR, Ax, Axis +from .types import TYPE_TAG_STR, Ax, Axis, PriorityMode from .validators import validate_name_str from .viz import add_ax_if_none, equal_aspect @@ -36,12 +41,6 @@ except ImportError: gdstk_available = False -try: - gdspy_available = True - import gdspy -except ImportError: - gdspy_available = False - class AbstractStructure(Tidy3dBaseModel): """ @@ -75,6 +74,16 @@ class AbstractStructure(Tidy3dBaseModel): "``Simulation`` by default to compute the shape derivatives.", ) + priority: int = pydantic.Field( + None, + title="Priority", + description="Priority of the structure applied in structure overlapping region. " + "The material property in the overlapping region is dictated by the structure " + "of higher priority. For structures of equal priority, " + "the structure added later to the structure list takes precedence. When `priority` is None, " + "the value is automatically assigned based on `structure_priority_mode` in the `Simulation`.", + ) + @pydantic.root_validator(skip_on_failure=True) def _handle_background_mediums(cls, values): """Handle background medium combinations, including deprecation.""" @@ -110,6 +119,27 @@ def _transformed_slanted_polyslabs_not_allowed(cls, val): validate_no_transformed_polyslabs(val) return val + def _priority(self, priority_mode: PriorityMode) -> int: + """Priority of this structure. The priority value is set automatically based on `priority_modes, + if its original value is `None`. + """ + if self.priority is not None: + return self.priority + return 0 + + @staticmethod + def _sort_structures( + structures: list[StructureType], structure_priority_mode: PriorityMode + ) -> list[StructureType]: + """Sort structure lists based on their priority values in ascending order.""" + + def structure_comparator(struct1, struct2): + return struct1._priority(structure_priority_mode) - struct2._priority( + structure_priority_mode + ) + + return sorted(structures, key=cmp_to_key(structure_comparator)) + @property def viz_spec(self): return None @@ -117,7 +147,12 @@ def viz_spec(self): @equal_aspect @add_ax_if_none def plot( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None, **patch_kwargs + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + **patch_kwargs, ) -> Ax: """Plot structure's geometric cross section at single (x,y,z) coordinate. @@ -189,11 +224,25 @@ class Structure(AbstractStructure): discriminator=TYPE_TAG_STR, ) + def _priority(self, priority_mode: PriorityMode) -> int: + """Priority of this structure. The priority value is set automatically based on `priority_modes, + if its original value is `None`. + """ + if self.priority is not None: + return self.priority + + if priority_mode == "conductor": + if self.medium.is_pec: + return 100 + if isinstance(self.medium, LossyMetalMedium): + return 90 + return 0 + @property def viz_spec(self): return self.medium.viz_spec - def eps_diagonal(self, frequency: float, coords: Coords) -> Tuple[complex, complex, complex]: + def eps_diagonal(self, frequency: float, coords: Coords) -> tuple[complex, complex, complex]: """Main diagonal of the complex-valued permittivity tensor as a function of frequency. Parameters @@ -242,20 +291,20 @@ def _compatible_with(self, other: Structure) -> bool: """ Begin autograd code.""" @staticmethod - def get_monitor_name(index: int, data_type: str) -> str: + def _get_monitor_name(index: int, data_type: str) -> str: """Get the monitor name for either a field or permittivity monitor at given index.""" - monitor_name_map = dict( - fld=f"adjoint_fld_{index}", - eps=f"adjoint_eps_{index}", - ) + monitor_name_map = { + "fld": f"adjoint_fld_{index}", + "eps": f"adjoint_eps_{index}", + } if data_type not in monitor_name_map: raise KeyError(f"'data_type' must be in {monitor_name_map.keys()}") return monitor_name_map[data_type] - def make_adjoint_monitors( + def _make_adjoint_monitors( self, freqs: list[float], index: int, field_keys: list[str] ) -> (FieldMonitor, PermittivityMonitor): """Generate the field and permittivity monitor for this structure.""" @@ -264,24 +313,21 @@ def make_adjoint_monitors( box = geometry.bounding_box # we dont want these fields getting traced by autograd, otherwise it messes stuff up - size = [get_static(x) for x in box.size] center = [get_static(x) for x in box.center] - # polyslab only needs fields at the midpoint along axis - if ( - isinstance(geometry, PolySlab) - and not isinstance(self.medium, AbstractCustomMedium) - and field_keys == [("vertices",)] - ): - size[geometry.axis] = 0 + if contains("medium", field_keys): + interval_space = AUTOGRAD_MONITOR_INTERVAL_SPACE_CUSTOM + else: + interval_space = AUTOGRAD_MONITOR_INTERVAL_SPACE_POLY mnt_fld = FieldMonitor( size=size, center=center, freqs=freqs, fields=("Ex", "Ey", "Ez"), - name=self.get_monitor_name(index=index, data_type="fld"), + name=self._get_monitor_name(index=index, data_type="fld"), + interval_space=interval_space, colocate=False, ) @@ -289,13 +335,14 @@ def make_adjoint_monitors( size=size, center=center, freqs=freqs, - name=self.get_monitor_name(index=index, data_type="eps"), + name=self._get_monitor_name(index=index, data_type="eps"), + interval_space=interval_space, colocate=False, ) return mnt_fld, mnt_eps - def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: + def _compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldMap: """Compute adjoint gradients given the forward and adjoint fields""" # generate a mapping from the 'medium', or 'geometry' tag to the list of fields for VJP @@ -319,11 +366,11 @@ def compute_derivatives(self, derivative_info: DerivativeInfo) -> AutogradFieldM # grab derivative values {field_name -> vjp_value} med_or_geo_field = self.medium if med_or_geo == "medium" else self.geometry info = derivative_info.updated_copy(paths=field_paths, deep=False) - derivative_values_map = med_or_geo_field.compute_derivatives(derivative_info=info) + derivative_values_map = med_or_geo_field._compute_derivatives(derivative_info=info) # construct map of {field path -> derivative value} for field_path, derivative_value in derivative_values_map.items(): - path = tuple([med_or_geo] + list(field_path)) + path = (med_or_geo, *list(field_path)) derivative_map[path] = derivative_value return derivative_map @@ -355,9 +402,9 @@ def eps_comp(self, row: Axis, col: Axis, frequency: float, coords: Coords) -> co def to_gdstk( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, gds_layer: pydantic.NonNegativeInt = 0, @@ -421,49 +468,12 @@ def to_gdstk( return polygons - def to_gdspy( - self, - x: float = None, - y: float = None, - z: float = None, - gds_layer: pydantic.NonNegativeInt = 0, - gds_dtype: pydantic.NonNegativeInt = 0, - ) -> None: - """Convert a structure's planar slice to a .gds type polygon. - - Parameters - ---------- - x : float = None - Position of plane in x direction, only one of x,y,z can be specified to define plane. - y : float = None - Position of plane in y direction, only one of x,y,z can be specified to define plane. - z : float = None - Position of plane in z direction, only one of x,y,z can be specified to define plane. - gds_layer : int = 0 - Layer index to use for the shapes stored in the .gds file. - gds_dtype : int = 0 - Data-type index to use for the shapes stored in the .gds file. - - Return - ------ - List - List of ``gdspy.Polygon`` and ``gdspy.PolygonSet``. - """ - - if isinstance(self.medium, AbstractCustomMedium): - raise Tidy3dError( - "Structures with custom medium are not supported by 'gdspy'. They can only be " - "exported using 'to_gdstk'." - ) - - return self.geometry.to_gdspy(x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) - def to_gds( self, cell, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, gds_layer: pydantic.NonNegativeInt = 0, @@ -473,7 +483,7 @@ def to_gds( Parameters ---------- - cell : ``gdstk.Cell`` or ``gdspy.Cell`` + cell : ``gdstk.Cell`` Cell object to which the generated polygons are added. x : float = None Position of plane in x direction, only one of x,y,z can be specified to define plane. @@ -491,43 +501,31 @@ def to_gds( gds_dtype : int = 0 Data-type index to use for the shapes stored in the .gds file. """ - if gdstk_available and isinstance(cell, gdstk.Cell): - polygons = self.to_gdstk( - x=x, - y=y, - z=z, - permittivity_threshold=permittivity_threshold, - frequency=frequency, - gds_layer=gds_layer, - gds_dtype=gds_dtype, - ) - if len(polygons) > 0: - cell.add(*polygons) - - elif gdspy_available and isinstance(cell, gdspy.Cell): - polygons = self.to_gdspy(x=x, y=y, z=z, gds_layer=gds_layer, gds_dtype=gds_dtype) - if len(polygons) > 0: - cell.add(polygons) + if not isinstance(cell, gdstk.Cell): + if "gdstk" in cell.__class__.__name__.lower() and not gdstk_available: + raise Tidy3dImportError( + "Module 'gdstk' not found. It is required to export shapes to gdstk cells." + ) + raise Tidy3dImportError("Argument 'cell' must be an instance of 'gdstk.Cell'.") - elif "gdstk" in cell.__class__ and not gdstk_available: - raise Tidy3dImportError( - "Module 'gdstk' not found. It is required to export shapes to gdstk cells." - ) - elif "gdspy" in cell.__class__ and not gdspy_available: - raise Tidy3dImportError( - "Module 'gdspy' not found. It is required to export shapes to gdspy cells." - ) - else: - raise Tidy3dError( - "Argument 'cell' must be an instance of 'gdstk.Cell' or 'gdspy.Cell'." - ) + polygons = self.to_gdstk( + x=x, + y=y, + z=z, + permittivity_threshold=permittivity_threshold, + frequency=frequency, + gds_layer=gds_layer, + gds_dtype=gds_dtype, + ) + if polygons: + cell.add(*polygons) def to_gds_file( self, fname: str, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pydantic.NonNegativeFloat = 1, frequency: pydantic.PositiveFloat = 0, gds_layer: pydantic.NonNegativeInt = 0, @@ -558,15 +556,15 @@ def to_gds_file( gds_cell_name : str = 'MAIN' Name of the cell created in the .gds file to store the geometry. """ - if gdstk_available: + try: + import gdstk + library = gdstk.Library() - elif gdspy_available: - library = gdspy.GdsLibrary() - else: + except ImportError as e: raise Tidy3dImportError( - "Python modules 'gdspy' and 'gdstk' not found. To export geometries to .gds " - "files, please install one of those those modules." - ) + "Python module 'gdstk' not found. To export geometries to .gds " + "files, please install it." + ) from e cell = library.new_cell(gds_cell_name) self.to_gds( cell, @@ -659,7 +657,7 @@ class MeshOverrideStructure(AbstractStructure): >>> struct_override = MeshOverrideStructure(geometry=box, dl=(0.1,0.2,0.3), name='override_box') """ - dl: Tuple[ + dl: tuple[ Optional[pydantic.PositiveFloat], Optional[pydantic.PositiveFloat], Optional[pydantic.PositiveFloat], @@ -670,6 +668,13 @@ class MeshOverrideStructure(AbstractStructure): units=MICROMETER, ) + priority: int = pydantic.Field( + 0, + title="Priority", + description="Priority of the structure applied in mesh override structure overlapping region. " + "The priority of internal override structures is ``-1``.", + ) + enforce: bool = pydantic.Field( False, title="Enforce Grid Size", diff --git a/tidy3d/components/subpixel_spec.py b/tidy3d/components/subpixel_spec.py index 1781b04876..091f65e933 100644 --- a/tidy3d/components/subpixel_spec.py +++ b/tidy3d/components/subpixel_spec.py @@ -120,6 +120,14 @@ class PECConformal(AbstractSubpixelAveragingMethod): ge=0, ) + edge_singularity_correction: bool = pd.Field( + False, + title="Apply Singularity Model At Metal Edges", + description="Apply field correction model at metallic edges where field singularity occurs. " + "The edges should be straight, and aligned with the primal grids; and the wedge angle is either " + "0 or 90 degree.", + ) + @cached_property def courant_ratio(self) -> float: """The scaling ratio applied to Courant number so that the courant number @@ -129,6 +137,7 @@ def courant_ratio(self) -> float: PECSubpixelType = Union[Staircasing, HeuristicPECStaircasing, PECConformal] +PMCSubpixelType = Union[Staircasing, HeuristicPECStaircasing] class SurfaceImpedance(PECConformal): @@ -176,6 +185,13 @@ class SubpixelSpec(Tidy3dBaseModel): discriminator=TYPE_TAG_STR, ) + pmc: PMCSubpixelType = pd.Field( + Staircasing(), + title="Subpixel Averaging Method For PMC Interfaces", + description="Subpixel averaging method applied to PMC structure interfaces.", + discriminator=TYPE_TAG_STR, + ) + lossy_metal: LossyMetalSubpixelType = pd.Field( SurfaceImpedance(), title="Subpixel Averaging Method for Lossy Metal Interfaces", @@ -190,6 +206,7 @@ def staircasing(cls) -> SubpixelSpec: dielectric=Staircasing(), metal=Staircasing(), pec=Staircasing(), + pmc=Staircasing(), lossy_metal=Staircasing(), ) diff --git a/tidy3d/components/tcad/analysis/__init__.py b/tidy3d/components/tcad/analysis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tidy3d/components/tcad/analysis/heat_simulation_type.py b/tidy3d/components/tcad/analysis/heat_simulation_type.py new file mode 100644 index 0000000000..154f10dce2 --- /dev/null +++ b/tidy3d/components/tcad/analysis/heat_simulation_type.py @@ -0,0 +1,64 @@ +"""Dealing with time specifications for DeviceSimulation""" + +from __future__ import annotations + +import pydantic.v1 as pd + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.constants import KELVIN, SECOND + + +class UnsteadySpec(Tidy3dBaseModel): + """Defines an unsteady specification + + Example + -------- + >>> import tidy3d as td + >>> time_spec = td.UnsteadySpec( + ... time_step=0.01, + ... total_time_steps=200, + ... ) + """ + + time_step: pd.PositiveFloat = pd.Field( + ..., + title="Time-step", + description="Time step taken for each iteration of the time integration loop.", + units=SECOND, + ) + + total_time_steps: pd.PositiveInt = pd.Field( + ..., + title="Total time steps", + description="Specifies the total number of time steps run during the simulation.", + ) + + +class UnsteadyHeatAnalysis(Tidy3dBaseModel): + """ + Configures relevant unsteady-state heat simulation parameters. + + Example + ------- + >>> import tidy3d as td + >>> time_spec = td.UnsteadyHeatAnalysis( + ... initial_temperature=300, + ... unsteady_spec=td.UnsteadySpec( + ... time_step=0.01, + ... total_time_steps=200, + ... ), + ... ) + """ + + initial_temperature: pd.PositiveFloat = pd.Field( + ..., + title="Initial temperature.", + description="Initial value for the temperature field.", + units=KELVIN, + ) + + unsteady_spec: UnsteadySpec = pd.Field( + ..., + title="Unsteady specification", + description="Time step and total time steps for the unsteady simulation.", + ) diff --git a/tidy3d/components/tcad/bandgap.py b/tidy3d/components/tcad/bandgap.py index 61b469252c..55c2cedafc 100644 --- a/tidy3d/components/tcad/bandgap.py +++ b/tidy3d/components/tcad/bandgap.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel diff --git a/tidy3d/components/tcad/boundary/charge.py b/tidy3d/components/tcad/boundary/charge.py index b31dac4917..3ce5cf7228 100644 --- a/tidy3d/components/tcad/boundary/charge.py +++ b/tidy3d/components/tcad/boundary/charge.py @@ -62,8 +62,8 @@ class InsulatingBC(HeatChargeBC): Notes ----- - Ensures the electric potential to the normal :math:`\\nabla \\psi \\dot \\mathbf{n} = 0` as well as the - surface recombination current density :math:`J_s = \\mathbf{J} \\dot \\mathbf{n} = 0` are set to zero where + Ensures the electric potential to the normal :math:`\\nabla \\psi \\cdot \\mathbf{n} = 0` as well as the + surface recombination current density :math:`J_s = \\mathbf{J} \\cdot \\mathbf{n} = 0` are set to zero where the current density is :math:`\\mathbf{J_n}` and the normal vector is :math:`\\mathbf{n}` Example diff --git a/tidy3d/components/tcad/data/monitor_data/abstract.py b/tidy3d/components/tcad/data/monitor_data/abstract.py index 6deab4014f..63027f261f 100644 --- a/tidy3d/components/tcad/data/monitor_data/abstract.py +++ b/tidy3d/components/tcad/data/monitor_data/abstract.py @@ -4,7 +4,7 @@ import copy from abc import ABC, abstractmethod -from typing import Tuple, Union +from typing import Union import numpy as np import pydantic.v1 as pd @@ -34,7 +34,7 @@ class HeatChargeMonitorData(AbstractMonitorData, ABC): description="Monitor associated with the data.", ) - symmetry: Tuple[ScalarSymmetry, ScalarSymmetry, ScalarSymmetry] = pd.Field( + symmetry: tuple[ScalarSymmetry, ScalarSymmetry, ScalarSymmetry] = pd.Field( (0, 0, 0), title="Symmetry", description="Symmetry of the original simulation in x, y, and z.", diff --git a/tidy3d/components/tcad/data/monitor_data/charge.py b/tidy3d/components/tcad/data/monitor_data/charge.py index d3a3f9738c..8a08fdbe97 100644 --- a/tidy3d/components/tcad/data/monitor_data/charge.py +++ b/tidy3d/components/tcad/data/monitor_data/charge.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Union +from typing import Union import numpy as np import pydantic.v1 as pd @@ -10,7 +10,9 @@ from tidy3d.components.base import skip_if_fields_missing from tidy3d.components.data.data_array import ( DataArray, + IndexedFieldVoltageDataArray, IndexedVoltageDataArray, + PointDataArray, SpatialDataArray, SteadyVoltageDataArray, ) @@ -18,6 +20,7 @@ from tidy3d.components.tcad.data.monitor_data.abstract import HeatChargeMonitorData from tidy3d.components.tcad.monitors.charge import ( SteadyCapacitanceMonitor, + SteadyElectricFieldMonitor, SteadyEnergyBandMonitor, SteadyFreeCarrierMonitor, SteadyPotentialMonitor, @@ -50,9 +53,9 @@ class SteadyPotentialData(HeatChargeMonitorData): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" - return dict(potential=self.potential) + return {"potential": self.potential} @pd.validator("potential", always=True) @skip_if_fields_missing(["monitor"]) @@ -118,9 +121,9 @@ class SteadyFreeCarrierData(HeatChargeMonitorData): # p = holes @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" - return dict(electrons=self.electrons, holes=self.holes) + return {"electrons": self.electrons, "holes": self.holes} @pd.root_validator(skip_on_failure=True) def check_correct_data_type(cls, values): @@ -234,9 +237,9 @@ class SteadyEnergyBandData(HeatChargeMonitorData): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" - return dict(Ec=self.Ec, Ev=self.Ev, Ei=self.Ei, Efn=self.Efn, Efp=self.Efp) + return {"Ec": self.Ec, "Ev": self.Ev, "Ei": self.Ei, "Efn": self.Efn, "Efp": self.Efp} @pd.root_validator(skip_on_failure=True) def check_correct_data_type(cls, values): @@ -318,7 +321,7 @@ def plot(self, ax: Ax = None, **sel_kwargs) -> Ax: The supplied or created matplotlib axes. """ - selection_data = dict() + selection_data = {} if ("voltage" not in sel_kwargs) and (self.Ec.values.coords.sizes["voltage"] > 1): raise DataError( @@ -460,3 +463,82 @@ def symmetry_expanded_copy(self) -> SteadyCapacitanceData: electron_capacitance=new_electron_capacitance, symmetry=(0, 0, 0), ) + + +class SteadyElectricFieldData(HeatChargeMonitorData): + """ + Stores electric field :math:`\\vec{E}` from a charge simulation. + + Notes + ----- + The electric field is computed as the negative gradient of the electric potential :math:`\\vec{E} = -\\nabla \\psi`. + It is given in units of :math:`V/\\mu m` (Volts per micrometer). + """ + + monitor: SteadyElectricFieldMonitor = pd.Field( + ..., + title="Electric field monitor", + description="Electric field data associated with a Charge simulation.", + ) + + E: UnstructuredFieldType = pd.Field( + None, + title="Electric field", + description=r"Contains the computed electric field in :math:`V/\\mu m`.", + discriminator=TYPE_TAG_STR, + ) + + @property + def field_components(self) -> dict[str, UnstructuredFieldType]: + """Maps the field components to their associated data.""" + return {"E": self.E} + + @pd.root_validator(skip_on_failure=True) + def warn_no_data(cls, values): + """Warn if no data provided.""" + + mnt = values.get("monitor") + E = values.get("E") + + if E is None: + log.warning( + f"No data is available for monitor '{mnt.name}'. This is typically caused by " + "monitor not intersecting any solid medium." + ) + + return values + + @pd.root_validator(skip_on_failure=True) + def check_correct_data_type(cls, values): + """Issue error if incorrect data type is used""" + + mnt = values.get("monitor") + E = values.get("E") + + if isinstance(E, TetrahedralGridDataset) or isinstance(E, TriangularGridDataset): + AcceptedTypes = (IndexedFieldVoltageDataArray, PointDataArray) + if not isinstance(E.values, AcceptedTypes): + raise ValueError( + f"In the data associated with monitor {mnt}, must contain a field. This can be " + "defined with IndexedFieldVoltageDataArray or PointDataArray." + ) + + return values + + @property + def symmetry_expanded_copy(self) -> SteadyElectricFieldData: + """Return copy of self with symmetry applied.""" + + new_E = self._symmetry_expanded_copy(property=self.E) + + return self.updated_copy( + E=new_E, + symmetry=(0, 0, 0), + ) + + def field_name(self, val: str = "") -> str: + """Gets the name of the fields to be plotted.""" + if val == "abs^2": + return "E²" + else: + return "E" diff --git a/tidy3d/components/tcad/data/monitor_data/heat.py b/tidy3d/components/tcad/data/monitor_data/heat.py index eac51a52b0..13a7991936 100644 --- a/tidy3d/components/tcad/data/monitor_data/heat.py +++ b/tidy3d/components/tcad/data/monitor_data/heat.py @@ -2,14 +2,14 @@ from __future__ import annotations -from typing import Dict, Optional, Union +from typing import Optional, Union import pydantic.v1 as pd from tidy3d.components.base import skip_if_fields_missing from tidy3d.components.data.data_array import ( DataArray, - IndexedDataArray, + ScalarFieldTimeDataArray, SpatialDataArray, ) from tidy3d.components.data.utils import TetrahedralGridDataset, TriangularGridDataset @@ -22,7 +22,9 @@ from tidy3d.log import log FieldDataset = Union[ - SpatialDataArray, annotate_type(Union[TriangularGridDataset, TetrahedralGridDataset]) + SpatialDataArray, + ScalarFieldTimeDataArray, + annotate_type(Union[TriangularGridDataset, TetrahedralGridDataset]), ] UnstructuredFieldType = Union[TriangularGridDataset, TetrahedralGridDataset] @@ -56,9 +58,9 @@ class TemperatureData(HeatChargeMonitorData): ) @property - def field_components(self) -> Dict[str, DataArray]: + def field_components(self) -> dict[str, DataArray]: """Maps the field components to their associated data.""" - return dict(temperature=self.temperature) + return {"temperature": self.temperature} @pd.validator("temperature", always=True) @skip_if_fields_missing(["monitor"]) @@ -75,22 +77,6 @@ def warn_no_data(cls, val, values): return val - @pd.validator("temperature", always=True) - @skip_if_fields_missing(["monitor"]) - def check_correct_data_type(cls, val, values): - """Issue error if incorrect data type is used""" - - mnt = values.get("monitor") - - if isinstance(val, TetrahedralGridDataset) or isinstance(val, TriangularGridDataset): - if not isinstance(val.values, IndexedDataArray): - raise ValueError( - f"Monitor {mnt} of type 'TemperatureMonitor' cannot be associated with data arrays " - "of type 'IndexVoltageDataArray'." - ) - - return val - def field_name(self, val: str = "") -> str: """Gets the name of the fields to be plot.""" if val == "abs^2": diff --git a/tidy3d/components/tcad/data/monitor_data/mesh.py b/tidy3d/components/tcad/data/monitor_data/mesh.py new file mode 100644 index 0000000000..e15b242103 --- /dev/null +++ b/tidy3d/components/tcad/data/monitor_data/mesh.py @@ -0,0 +1,70 @@ +"""Monitor data for unstructured volume mesh monitors.""" + +from __future__ import annotations + +from typing import Union + +import pydantic.v1 as pd + +from tidy3d.components.data.utils import TetrahedralGridDataset, TriangularGridDataset +from tidy3d.components.tcad.data.monitor_data.abstract import HeatChargeMonitorData +from tidy3d.components.tcad.monitors.mesh import VolumeMeshMonitor + +UnstructuredFieldType = Union[TriangularGridDataset, TetrahedralGridDataset] + + +class VolumeMeshData(HeatChargeMonitorData): + """Data associated with a :class:`VolumeMeshMonitor`: stores the unstructured mesh. + + Example + ------- + + >>> import tidy3d as td + >>> import numpy as np + >>> mesh_mnt = td.VolumeMeshMonitor(size=(1, 2, 3), name="mesh") + >>> tet_grid_points = td.PointDataArray( + ... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + ... dims=("index", "axis"), + ... ) + >>> tet_grid_cells = td.CellDataArray( + ... [[0, 1, 2, 4], [1, 2, 3, 4]], + ... dims=("cell_index", "vertex_index"), + ... ) + >>> tet_grid_values = td.IndexedDataArray( + ... np.zeros((tet_grid_points.shape[0],)), + ... dims=("index",), + ... name="Mesh", + ... ) + >>> tet_grid = td.TetrahedralGridDataset( + ... points=tet_grid_points, + ... cells=tet_grid_cells, + ... values=tet_grid_values, + ... ) + >>> mesh_mnt_data = td.VolumeMeshData(monitor=mesh_mnt, mesh=tet_grid) # doctest: +SKIP + """ + + monitor: VolumeMeshMonitor = pd.Field( + ..., title="Monitor", description="Mesh monitor associated with the data." + ) + + mesh: UnstructuredFieldType = pd.Field( + ..., + title="Mesh", + description="Dataset storing the mesh.", + ) + + @property + def field_components(self) -> dict[str, UnstructuredFieldType]: + """Maps the field components to their associated data.""" + return {"mesh": self.mesh} + + def field_name(self, val: str) -> str: + """Gets the name of the fields to be plot.""" + return "Mesh" + + @property + def symmetry_expanded_copy(self) -> VolumeMeshData: + """Return copy of self with symmetry applied.""" + + new_mesh = self._symmetry_expanded_copy(property=self.mesh) + return self.updated_copy(mesh=new_mesh, symmetry=(0, 0, 0)) diff --git a/tidy3d/components/tcad/data/sim_data.py b/tidy3d/components/tcad/data/sim_data.py index 0a9a8e4898..e46840a1e0 100644 --- a/tidy3d/components/tcad/data/sim_data.py +++ b/tidy3d/components/tcad/data/sim_data.py @@ -2,11 +2,13 @@ from __future__ import annotations -from typing import Optional, Tuple +from abc import ABC +from typing import Literal, Optional import numpy as np import pydantic.v1 as pd +from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.base_sim.data.sim_data import AbstractSimulationData from tidy3d.components.data.data_array import ( SpatialDataArray, @@ -17,20 +19,21 @@ TriangularGridDataset, UnstructuredGridDataset, ) +from tidy3d.components.tcad.data.monitor_data.mesh import VolumeMeshData from tidy3d.components.tcad.data.types import ( SteadyPotentialData, TCADMonitorDataType, TemperatureData, ) +from tidy3d.components.tcad.mesher import VolumeMesher +from tidy3d.components.tcad.monitors.mesh import VolumeMeshMonitor from tidy3d.components.tcad.simulation.heat import HeatSimulation from tidy3d.components.tcad.simulation.heat_charge import HeatChargeSimulation -from tidy3d.components.types import Ax, Literal, RealFieldVal, annotate_type +from tidy3d.components.types import Ax, RealFieldVal, annotate_type from tidy3d.components.viz import add_ax_if_none, equal_aspect -from tidy3d.exceptions import DataError +from tidy3d.exceptions import DataError, Tidy3dKeyError from tidy3d.log import log -from ...base import Tidy3dBaseModel - class DeviceCharacteristics(Tidy3dBaseModel): """Stores device characteristics. For example, in steady-state it stores @@ -73,8 +76,132 @@ class DeviceCharacteristics(Tidy3dBaseModel): description="Device steady DC current-voltage relation for the device.", ) + steady_dc_resistance_voltage: Optional[SteadyVoltageDataArray] = pd.Field( + None, + title="Small signal resistance", + description="Steady DC computation of the small signal resistance. This is computed " + "as the derivative of the current-voltage relation, delta(V)/delta(I) and the result " + "is given in Ohms. Note that in 2D the resistance is given in :math:`\\Omega \\mu`.", + ) + + +class AbstractHeatChargeSimulationData(AbstractSimulationData, ABC): + """Abstract class for HeatChargeSimulation results, or VolumeMesher results.""" + + simulation: HeatChargeSimulation = pd.Field( + title="Heat-Charge Simulation", + description="Original :class:`.HeatChargeSimulation` associated with the data.", + ) + + @staticmethod + def _get_field_by_name(monitor_data: TCADMonitorDataType, field_name: Optional[str] = None): + """Return a field data based on a monitor dataset and a specified field name.""" + if field_name is None: + if len(monitor_data.field_components) > 1: + raise DataError( + "'field_name' must be specified for datasets that store more than one field." + ) + field_name = next(iter(monitor_data.field_components)) + + if field_name not in monitor_data.field_components.keys(): + raise DataError(f"field_name '{field_name}' not found in data.") + + field = monitor_data.field_components[field_name] + if field is None: + raise DataError(f"Field {field_name} is empty.") + + return field + + @equal_aspect + @add_ax_if_none + def plot_mesh( + self, + monitor_name: str, + field_name: Optional[str] = None, + structures_fill: bool = True, + ax: Ax = None, + **sel_kwargs, + ) -> Ax: + """Plot the simulation mesh in a monitor region with structures overlaid. + + Parameters + ---------- + monitor_name : str + Name of :class:`.HeatChargeMonitor` to plot. Must be a monitor with the `unstructured=True` setting. + field_name : Optional[str] = "mesh" + Name of ``field`` component whose associated grid to plot. Not required if monitor data contains only one field. + structures_fill : bool = True + Whether to overlay the mesh on structures filled with color or only show structure outlines. + ax : matplotlib.axes._subplots.Axes = None + matplotlib axes to plot on, if not specified, one is created. + sel_kwargs : keyword arguments used to perform ``.sel()`` selection in the monitor data. + These kwargs can select over the spatial dimensions (``x``, ``y``, ``z``), + or time dimension (``t``) if applicable. + For the plotting to work appropriately, the resulting data after selection must contain + only two coordinates with len > 1. + Furthermore, these should be spatial coordinates (``x``, ``y``, or ``z``). + + Note + ---- + For 3D simulations, the 2D mesh shown here would be the result of slicing the underlying unstructured tetrahedral grid with the selected plane. + If however the monitor sets `conformal=True`, the simulation mesh has been made to conform to the monitor plane, in which case the visualized mesh is exact. + + Returns + ------- + matplotlib.axes._subplots.Axes + The supplied or created matplotlib axes. + """ + + monitor_data = self[monitor_name] + + if not monitor_data.monitor.unstructured: + raise DataError("'plot_mesh' can only be used with unstructured-grid monitors.") + + field_data = self._get_field_by_name(monitor_data=monitor_data, field_name=field_name) + + # do sel on unstructured data + if len(sel_kwargs) > 0: + field_data = field_data.sel(**sel_kwargs) + + if isinstance(field_data, TetrahedralGridDataset): + raise DataError( + "Must select a two-dimensional slice of unstructured dataset for plotting" + " on a plane." + ) + + # compute parameters for structures plot + axis = field_data.normal_axis + position = field_data.normal_pos + + # compute plot bounds + field_data_bounds = field_data.bounds + min_bounds = list(field_data_bounds[0]) + max_bounds = list(field_data_bounds[1]) + min_bounds.pop(axis) + max_bounds.pop(axis) + + # select the cross section data + interp_kwarg = {"xyz"[axis]: position} + # plot the simulation structures first, because we don't use alpha + ax = self.simulation.scene.plot_structures( + ax=ax, + fill=structures_fill, + hlim=(min_bounds[0], max_bounds[0]), + vlim=(min_bounds[1], max_bounds[1]), + **interp_kwarg, + ) + + # only then overlay the mesh plot + field_data.plot(ax=ax, cmap=False, field=False, grid=True) + + # set the limits based on the xarray coordinates min and max + ax.set_xlim(min_bounds[0], max_bounds[0]) + ax.set_ylim(min_bounds[1], max_bounds[1]) + + return ax -class HeatChargeSimulationData(AbstractSimulationData): + +class HeatChargeSimulationData(AbstractHeatChargeSimulationData): """Stores results of a :class:`HeatChargeSimulation`. Example @@ -118,12 +245,7 @@ class HeatChargeSimulationData(AbstractSimulationData): ... ) """ - simulation: HeatChargeSimulation = pd.Field( - title="Heat-Charge Simulation", - description="Original :class:`.HeatChargeSimulation` associated with the data.", - ) - - data: Tuple[annotate_type(TCADMonitorDataType), ...] = pd.Field( + data: tuple[annotate_type(TCADMonitorDataType), ...] = pd.Field( ..., title="Monitor Data", description="List of :class:`.MonitorData` instances " @@ -147,17 +269,17 @@ def plot_field( scale: Literal["lin", "log"] = "lin", structures_alpha: float = 0.2, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, **sel_kwargs, ) -> Ax: - """Plot the data for a monitor with simulation plot overlaid. + """Plot the data for a monitor with simulation structures overlaid. Parameters ---------- - field_monitor_name : str - Name of :class:`.TemperatureMonitorData` to plot. + monitor_name : str + Name of :class:`.HeatChargeMonitor` to plot. field_name : Optional[Literal["temperature", "potential"]] = None Name of ``field`` component to plot (eg. `'temperature'`). Not required if monitor data contains only one field. val : Literal['real', 'abs', 'abs^2'] = 'real' @@ -165,8 +287,8 @@ def plot_field( scale : Literal['lin', 'log'] Plot in linear or logarithmic scale. structures_alpha : float = 0.2 - Opacity of the structure permittivity. - Must be between 0 and 1 (inclusive). + Opacity of the structure property to plot (heat conductivity or electric conductivity + depending on the type of monitor). Must be between 0 and 1 (inclusive). robust : bool = True If True and vmin or vmax are absent, uses the 2nd and 98th percentiles of the data to compute the color limits. This helps in visualizing the field patterns especially @@ -195,23 +317,13 @@ def plot_field( monitor_data = self[monitor_name] property_to_plot = None - if field_name is None: - if isinstance(monitor_data, TemperatureData): - field_name = "temperature" - elif isinstance(monitor_data, SteadyPotentialData): - field_name = "potential" + field = self._get_field_by_name(monitor_data=monitor_data, field_name=field_name) - if field_name not in monitor_data.field_components.keys(): - raise DataError(f"field_name '{field_name}' not found in data.") - - field = monitor_data.field_components[field_name] - if field is None: - raise DataError(f"Field {field_name} is empty and cannot be plotted.") # forward field name to actual data so it gets displayed # field.name = field_name field_data = self._field_component_value(field, val) - if isinstance(monitor_data, TemperatureData): + if isinstance(monitor_data, (TemperatureData, VolumeMeshData)): property_to_plot = "heat_conductivity" elif isinstance(monitor_data, SteadyPotentialData): property_to_plot = "electric_conductivity" @@ -270,7 +382,7 @@ def plot_field( if field_data.coords[axis].size <= 1: field_data = field_data.sel(**{axis: pos}, method="nearest") else: - field_data = field_data.interp(**{axis: pos}, kwargs=dict(bounds_error=True)) + field_data = field_data.interp(**{axis: pos}, kwargs={"bounds_error": True}) # select the extra coordinates out of the data from user-specified kwargs for coord_name, coord_val in sel_kwargs.items(): @@ -278,7 +390,7 @@ def plot_field( field_data = field_data.sel(**{coord_name: coord_val}, method=None) else: field_data = field_data.interp( - **{coord_name: coord_val}, kwargs=dict(bounds_error=True) + **{coord_name: coord_val}, kwargs={"bounds_error": True} ) field_data = field_data.squeeze(drop=True) @@ -369,3 +481,106 @@ def issue_warning_deprecated(cls, values): "'HeatChargeSimulationData' instead" ) return values + + +class VolumeMesherData(AbstractHeatChargeSimulationData): + """Stores results of a :class:`VolumeMesher`. + + Example + ------- + >>> import tidy3d as td + >>> import numpy as np + >>> mesh_mnt = td.VolumeMeshMonitor(size=(1, 2, 3), name="mesh") + >>> temp_mnt = td.TemperatureMonitor(size=(1, 2, 3), name="sample") + >>> heat_sim = td.HeatChargeSimulation( + ... size=(3.0, 3.0, 3.0), + ... structures=[ + ... td.Structure( + ... geometry=td.Box(size=(1, 1, 1), center=(0, 0, 0)), + ... medium=td.Medium( + ... permittivity=2.0, heat_spec=td.SolidSpec( + ... conductivity=1, + ... capacity=1, + ... ) + ... ), + ... name="box", + ... ), + ... ], + ... medium=td.Medium(permittivity=3.0, heat_spec=td.FluidSpec()), + ... grid_spec=td.UniformUnstructuredGrid(dl=0.1), + ... sources=[td.HeatSource(rate=1, structures=["box"])], + ... boundary_spec=[ + ... td.HeatChargeBoundarySpec( + ... placement=td.StructureBoundary(structure="box"), + ... condition=td.TemperatureBC(temperature=500), + ... ) + ... ], + ... monitors=[temp_mnt], + ... ) + >>> tet_grid_points = td.PointDataArray( + ... [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [0.0, 0.0, 1.0]], + ... dims=("index", "axis"), + ... ) + >>> tet_grid_cells = td.CellDataArray( + ... [[0, 1, 2, 4], [1, 2, 3, 4]], + ... dims=("cell_index", "vertex_index"), + ... ) + >>> tet_grid_values = td.IndexedDataArray( + ... np.zeros((tet_grid_points.shape[0],)), + ... dims=("index",), + ... name="Mesh", + ... ) + >>> tet_grid = td.TetrahedralGridDataset( + ... points=tet_grid_points, + ... cells=tet_grid_cells, + ... values=tet_grid_values, + ... ) + >>> mesh_mnt_data = td.VolumeMeshData(monitor=mesh_mnt, mesh=tet_grid) # doctest: +SKIP + >>> mesh_data = td.VolumeMesherData(simulation=heat_sim, data=[mesh_mnt_data], monitors=[mesh_mnt]) # doctest: +SKIP + """ + + monitors: tuple[VolumeMeshMonitor, ...] = pd.Field( + ..., + title="Monitors", + description="List of monitors to be used for the mesher.", + ) + + data: tuple[VolumeMeshData, ...] = pd.Field( + ..., + title="Monitor Data", + description="List of :class:`.MonitorData` instances " + "associated with the monitors of the original :class:`.VolumeMesher`.", + ) + + @property + def mesher(self) -> VolumeMesher: + """Get the mesher associated with this mesher data.""" + return VolumeMesher( + simulation=self.simulation, + monitors=self.monitors, + ) + + @pd.root_validator(skip_on_failure=True) + def data_monitors_match_sim(cls, values): + """Ensure each :class:`AbstractMonitorData` in ``.data`` corresponds to a monitor in + ``.simulation``. + """ + monitors = values.get("monitors") + data = values.get("data") + mnt_names = {mnt.name for mnt in monitors} + + for mnt_data in data: + monitor_name = mnt_data.monitor.name + if monitor_name not in mnt_names: + raise DataError( + f"Data with monitor name '{monitor_name}' supplied " + f"but not found in the list of monitors." + ) + return values + + def get_monitor_by_name(self, name: str) -> VolumeMeshMonitor: + """Return monitor named 'name'.""" + for monitor in self.monitors: + if monitor.name == name: + return monitor + raise Tidy3dKeyError(f"No monitor named '{name}'") diff --git a/tidy3d/components/tcad/data/types.py b/tidy3d/components/tcad/data/types.py index c1865d309e..cb2045584d 100644 --- a/tidy3d/components/tcad/data/types.py +++ b/tidy3d/components/tcad/data/types.py @@ -6,6 +6,7 @@ from tidy3d.components.tcad.data.monitor_data.charge import ( SteadyCapacitanceData, + SteadyElectricFieldData, SteadyEnergyBandData, SteadyFreeCarrierData, SteadyPotentialData, @@ -16,6 +17,7 @@ TemperatureData, SteadyPotentialData, SteadyFreeCarrierData, + SteadyElectricFieldData, SteadyEnergyBandData, SteadyCapacitanceData, ] diff --git a/tidy3d/components/tcad/doping.py b/tidy3d/components/tcad/doping.py index 9570af2a9a..3d0449e4a1 100644 --- a/tidy3d/components/tcad/doping.py +++ b/tidy3d/components/tcad/doping.py @@ -1,15 +1,16 @@ """File containing classes required for the setup of a DEVSIM case.""" +from __future__ import annotations + import numpy as np import pydantic.v1 as pd from tidy3d.components.base import cached_property from tidy3d.components.geometry.base import Box from tidy3d.components.types import Union +from tidy3d.constants import PERCMCUBE from tidy3d.exceptions import SetupError -from ...constants import PERCMCUBE - class AbstractDopingBox(Box): """Derived class from Box to deal with dopings""" @@ -33,7 +34,7 @@ def _get_indices_in_box(self, coords: dict, meshgrid: bool = True): dim_missing = len(list(coords.keys())) < 3 if dim_missing: for var_name in "xyz": - if var_name not in coords.keys(): + if var_name not in coords: coords[var_name] = [0] # work out whether the dimensions are 2D @@ -45,6 +46,10 @@ def _get_indices_in_box(self, coords: dict, meshgrid: bool = True): normal_axis = dim # normal_position = coords[var_name][0] + if all(len(coords[var_name]) == 1 for var_name in "xyz"): + # if all coordinates have 1 point, we don't assume 2D unless the box itself is. + normal_axis = None + # if provided coordinates are 3D, check if box is 2D if normal_axis is None: normal_axis = self._normal_dim() @@ -63,11 +68,11 @@ def _get_indices_in_box(self, coords: dict, meshgrid: bool = True): new_bounds[1][d] = np.inf # let's assume some of these coordinates may lay outside the box - indices_in_box = np.logical_and(X >= new_bounds[0][0], X <= new_bounds[1][0]) - indices_in_box = np.logical_and(indices_in_box, Y >= new_bounds[0][1]) - indices_in_box = np.logical_and(indices_in_box, Y <= new_bounds[1][1]) - indices_in_box = np.logical_and(indices_in_box, Z >= new_bounds[0][2]) - indices_in_box = np.logical_and(indices_in_box, Z <= new_bounds[1][2]) + indices_in_box = np.logical_and(new_bounds[0][0] <= X, new_bounds[1][0] >= X) + indices_in_box = np.logical_and(indices_in_box, new_bounds[0][1] <= Y) + indices_in_box = np.logical_and(indices_in_box, new_bounds[1][1] >= Y) + indices_in_box = np.logical_and(indices_in_box, new_bounds[0][2] <= Z) + indices_in_box = np.logical_and(indices_in_box, new_bounds[1][2] >= Z) return indices_in_box, X, Y, Z, normal_axis @@ -129,8 +134,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): slices = [slice(None)] * X.ndim slices[normal_axis] = 0 return contrib[tuple(slices)] - else: - return contrib + return contrib class GaussianDoping(AbstractDopingBox): @@ -230,7 +234,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # lower x face if self.source != "xmin": x0 = self.bounds[0][0] - indices = np.logical_and(X >= x0, X <= x0 + self.width) + indices = np.logical_and(x0 <= X, x0 + self.width >= X) indices = np.logical_and(indices, indices_in_box) x_contrib[indices] = np.exp( -(X[indices] - x0 - self.width) @@ -242,7 +246,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # higher x face if self.source != "xmax": x1 = self.bounds[1][0] - indices = np.logical_and(X >= x1 - self.width, X <= x1) + indices = np.logical_and(x1 - self.width <= X, x1 >= X) indices = np.logical_and(indices, indices_in_box) x_contrib[indices] = np.exp( -(X[indices] - x1 + self.width) @@ -259,7 +263,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # lower y face if self.source != "ymin": y0 = self.bounds[0][1] - indices = np.logical_and(Y >= y0, Y <= y0 + self.width) + indices = np.logical_and(y0 <= Y, y0 + self.width >= Y) indices = np.logical_and(indices, indices_in_box) y_contrib[indices] = np.exp( -(Y[indices] - y0 - self.width) @@ -271,7 +275,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # higher y face if self.source != "ymax": y1 = self.bounds[1][1] - indices = np.logical_and(Y >= y1 - self.width, Y <= y1) + indices = np.logical_and(y1 - self.width <= Y, y1 >= Y) indices = np.logical_and(indices, indices_in_box) y_contrib[indices] = np.exp( -(Y[indices] - y1 + self.width) @@ -288,7 +292,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # lower z face if self.source != "zmin": z0 = self.bounds[0][2] - indices = np.logical_and(Z >= z0, Z <= z0 + self.width) + indices = np.logical_and(z0 <= Z, z0 + self.width >= Z) indices = np.logical_and(indices, indices_in_box) z_contrib[indices] = np.exp( -(Z[indices] - z0 - self.width) @@ -300,7 +304,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): # higher z face if self.source != "zmax": z1 = self.bounds[1][2] - indices = np.logical_and(Z >= z1 - self.width, Z <= z1) + indices = np.logical_and(z1 - self.width <= Z, z1 >= Z) indices = np.logical_and(indices, indices_in_box) z_contrib[indices] = np.exp( -(Z[indices] - z1 + self.width) @@ -316,8 +320,7 @@ def _get_contrib(self, coords: dict, meshgrid: bool = True): slices = [slice(None)] * X.ndim slices[normal_axis] = 0 return total_contrib[tuple(slices)] - else: - return total_contrib + return total_contrib DopingBoxType = Union[ConstantDoping, GaussianDoping] diff --git a/tidy3d/components/tcad/generation_recombination.py b/tidy3d/components/tcad/generation_recombination.py index b33f8412e9..faa10d03e4 100644 --- a/tidy3d/components/tcad/generation_recombination.py +++ b/tidy3d/components/tcad/generation_recombination.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel diff --git a/tidy3d/components/tcad/grid.py b/tidy3d/components/tcad/grid.py index 5720f3d667..fcf0cf6f27 100644 --- a/tidy3d/components/tcad/grid.py +++ b/tidy3d/components/tcad/grid.py @@ -3,18 +3,17 @@ from __future__ import annotations from abc import ABC -from typing import Tuple, Union +from typing import Union import numpy as np import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing +from tidy3d.components.geometry.base import Box +from tidy3d.components.types import Coordinate, annotate_type from tidy3d.constants import MICROMETER from tidy3d.exceptions import ValidationError -from ..geometry.base import Box -from ..types import Coordinate, annotate_type - class UnstructuredGrid(Tidy3dBaseModel, ABC): """Abstract unstructured grid.""" @@ -56,7 +55,7 @@ class UniformUnstructuredGrid(UnstructuredGrid): description="Enforced minimum number of mesh segments per any side of an object.", ) - non_refined_structures: Tuple[str, ...] = pd.Field( + non_refined_structures: tuple[str, ...] = pd.Field( (), title="Structures Without Refinement", description="List of structures for which ``min_edges_per_circumference`` and " @@ -202,21 +201,21 @@ class DistanceUnstructuredGrid(UnstructuredGrid): "surface when computing distance values.", ) - uniform_grid_mediums: Tuple[str, ...] = pd.Field( + uniform_grid_mediums: tuple[str, ...] = pd.Field( (), title="Mediums With Uniform Refinement", description="List of mediums for which ``dl_interface`` will be enforced everywhere " "in the volume.", ) - non_refined_structures: Tuple[str, ...] = pd.Field( + non_refined_structures: tuple[str, ...] = pd.Field( (), title="Structures Without Refinement", description="List of structures for which ``dl_interface`` will not be enforced. " "``dl_bulk`` is used instead.", ) - mesh_refinements: Tuple[annotate_type(Union[GridRefinementRegion, GridRefinementLine]), ...] = ( + mesh_refinements: tuple[annotate_type(Union[GridRefinementRegion, GridRefinementLine]), ...] = ( pd.Field( (), title="Mesh refinement structures", diff --git a/tidy3d/components/tcad/mesher.py b/tidy3d/components/tcad/mesher.py new file mode 100644 index 0000000000..d35b465c9a --- /dev/null +++ b/tidy3d/components/tcad/mesher.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +import pydantic.v1 as pd + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.tcad.monitors.mesh import VolumeMeshMonitor +from tidy3d.components.tcad.simulation.heat_charge import HeatChargeSimulation, TCADAnalysisTypes + + +class VolumeMesher(Tidy3dBaseModel): + """Specification for a standalone volume mesher.""" + + simulation: HeatChargeSimulation = pd.Field( + ..., + title="Simulation", + description="HeatCharge simulation instance for the mesh specification.", + ) + + monitors: tuple[VolumeMeshMonitor, ...] = pd.Field( + (), + title="Monitors", + description="List of monitors to be used for the mesher.", + ) + + def _get_simulation_types(self) -> list[TCADAnalysisTypes]: + return [TCADAnalysisTypes.MESH] diff --git a/tidy3d/components/tcad/mobility.py b/tidy3d/components/tcad/mobility.py index 127d3cca47..0d3cc22042 100644 --- a/tidy3d/components/tcad/mobility.py +++ b/tidy3d/components/tcad/mobility.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import pydantic.v1 as pd from tidy3d.components.base import Tidy3dBaseModel diff --git a/tidy3d/components/tcad/monitors/abstract.py b/tidy3d/components/tcad/monitors/abstract.py index 6628079429..8c3fa91bbe 100644 --- a/tidy3d/components/tcad/monitors/abstract.py +++ b/tidy3d/components/tcad/monitors/abstract.py @@ -1,5 +1,7 @@ """Objects that define how data is recorded from simulation.""" +from __future__ import annotations + from abc import ABC import pydantic.v1 as pd diff --git a/tidy3d/components/tcad/monitors/charge.py b/tidy3d/components/tcad/monitors/charge.py index e575e30a86..dc56129346 100644 --- a/tidy3d/components/tcad/monitors/charge.py +++ b/tidy3d/components/tcad/monitors/charge.py @@ -1,5 +1,7 @@ """Objects that define how data is recorded from simulation.""" +from __future__ import annotations + from typing import Literal import pydantic.v1 as pd @@ -78,3 +80,22 @@ class SteadyCapacitanceMonitor(HeatChargeMonitor): title="Unstructured Grid", description="Return data on the original unstructured grid.", ) + + +class SteadyElectricFieldMonitor(HeatChargeMonitor): + """ + Electric field monitor for Charge simulations. + + Example + ------- + >>> import tidy3d as td + >>> electric_field_monitor_z0 = td.SteadyElectricFieldMonitor( + ... center=(0, 0.14, 0), size=(0.6, 0.3, 0), name="electric_field_z0", + ... ) + """ + + unstructured: Literal[True] = pd.Field( + True, + title="Unstructured Grid", + description="Return data on the original unstructured grid.", + ) diff --git a/tidy3d/components/tcad/monitors/heat.py b/tidy3d/components/tcad/monitors/heat.py index bacb84ec2a..3d8fff722b 100644 --- a/tidy3d/components/tcad/monitors/heat.py +++ b/tidy3d/components/tcad/monitors/heat.py @@ -1,7 +1,21 @@ """Objects that define how data is recorded from simulation.""" +from __future__ import annotations + +from pydantic.v1 import Field, PositiveInt + from tidy3d.components.tcad.monitors.abstract import HeatChargeMonitor class TemperatureMonitor(HeatChargeMonitor): """Temperature monitor.""" + + interval: PositiveInt = Field( + 1, + title="Interval", + description="Sampling rate of the monitor: number of time steps between each measurement. " + "Set ``interval`` to 1 for the highest possible resolution in time. " + "Higher integer values down-sample the data by measuring every ``interval`` time steps. " + "This can be useful for reducing data storage as needed by the application." + "NOTE: this is only relevant for unsteady (transient) Heat simulations. ", + ) diff --git a/tidy3d/components/tcad/monitors/mesh.py b/tidy3d/components/tcad/monitors/mesh.py new file mode 100644 index 0000000000..87106068d1 --- /dev/null +++ b/tidy3d/components/tcad/monitors/mesh.py @@ -0,0 +1,29 @@ +"""Objects that define how data is recorded from simulation.""" + +from __future__ import annotations + +from math import isclose +from typing import Literal + +import pydantic.v1 as pd + +from tidy3d.components.tcad.monitors.abstract import HeatChargeMonitor + + +class VolumeMeshMonitor(HeatChargeMonitor): + """Monitor recording the volume mesh. The monitor size must be either 2D or 3D. If a 2D monitor + is used in a 3D simulation, the sliced volumetric mesh on the plane of the monitor will be + stored as a ``TriangularGridDataset``.""" + + unstructured: Literal[True] = pd.Field( + True, + title="Unstructured Grid", + description="Return the original unstructured grid.", + ) + + @pd.validator("size", always=True) + def _at_least_2d(cls, val): + """Validate that the monitor has at least two non-zero dimensions.""" + if len([d for d in val if isclose(d, 0)]) > 1: + raise ValueError("'VolumeMeshMonitor' must have at least two nonzero dimensions.") + return val diff --git a/tidy3d/components/tcad/simulation/heat.py b/tidy3d/components/tcad/simulation/heat.py index 6304ed8630..ace1d8a855 100644 --- a/tidy3d/components/tcad/simulation/heat.py +++ b/tidy3d/components/tcad/simulation/heat.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Tuple +from typing import Optional import pydantic.v1 as pd @@ -60,16 +60,16 @@ def issue_warning_deprecated(cls, values): @add_ax_if_none def plot_heat_conductivity( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, colorbar: str = "conductivity", - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. diff --git a/tidy3d/components/tcad/simulation/heat_charge.py b/tidy3d/components/tcad/simulation/heat_charge.py index 60f57ffa1b..20817231fa 100644 --- a/tidy3d/components/tcad/simulation/heat_charge.py +++ b/tidy3d/components/tcad/simulation/heat_charge.py @@ -4,7 +4,7 @@ from __future__ import annotations from enum import Enum -from typing import Dict, List, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd @@ -37,6 +37,7 @@ from tidy3d.components.spice.sources.dc import DCVoltageSource from tidy3d.components.spice.types import ElectricalAnalysisType from tidy3d.components.structure import Structure +from tidy3d.components.tcad.analysis.heat_simulation_type import UnsteadyHeatAnalysis from tidy3d.components.tcad.boundary.specification import ( HeatBoundarySpec, HeatChargeBoundarySpec, @@ -92,7 +93,10 @@ ChargeSourceTypes = () ElectricBCTypes = (VoltageBC, CurrentBC, InsulatingBC) -AnalysisSpecType = ElectricalAnalysisType +AnalysisSpecType = Union[ElectricalAnalysisType, UnsteadyHeatAnalysis] + +# define some limits for transient heat simulations +TRANSIENT_HEAT_MAX_STEPS = 1000 class TCADAnalysisTypes(str, Enum): @@ -101,6 +105,7 @@ class TCADAnalysisTypes(str, Enum): HEAT = "Heat" CONDUCTION = "Conduction" CHARGE = "Charge" + MESH = "Mesh" class HeatChargeSimulation(AbstractSimulation): @@ -121,7 +126,16 @@ class HeatChargeSimulation(AbstractSimulation): .. math:: - -k \\cdot \\nabla(T) = q + -\\nabla \\cdot (-k \\nabla T) = q + + It is also possible to run transient heat simulations by specifying ``analysis_spec=UnsteadyHeatAnalysis(...)``. This adds + the temporal terms to the above equations: + + .. math:: + + \\frac{\\partial \\rho c_p T}{\\partial t} -\\nabla \\cdot (k \\nabla(T)) = q + + where :math:`\\rho` is the density and :math:`c_p` is the specific heat capacity of the medium. The steady-state electrical ``Conduction`` equation depends on the electric conductivity (:math:`\\sigma`) of a @@ -260,19 +274,19 @@ class HeatChargeSimulation(AbstractSimulation): Background medium of simulation, defaults to a standard dispersion-less :class:`Medium` if not specified. """ - sources: Tuple[annotate_type(HeatChargeSourceType), ...] = pd.Field( + sources: tuple[annotate_type(HeatChargeSourceType), ...] = pd.Field( (), title="Heat and Charge sources", description="List of heat and/or charge sources.", ) - monitors: Tuple[annotate_type(HeatChargeMonitorType), ...] = pd.Field( + monitors: tuple[annotate_type(HeatChargeMonitorType), ...] = pd.Field( (), title="Monitors", description="Monitors in the simulation.", ) - boundary_spec: Tuple[annotate_type(Union[HeatChargeBoundarySpec, HeatBoundarySpec]), ...] = ( + boundary_spec: tuple[annotate_type(Union[HeatChargeBoundarySpec, HeatBoundarySpec]), ...] = ( pd.Field( (), title="Boundary Condition Specifications", @@ -287,7 +301,7 @@ class HeatChargeSimulation(AbstractSimulation): discriminator=TYPE_TAG_STR, ) - symmetry: Tuple[ScalarSymmetry, ScalarSymmetry, ScalarSymmetry] = pd.Field( + symmetry: tuple[ScalarSymmetry, ScalarSymmetry, ScalarSymmetry] = pd.Field( (0, 0, 0), title="Symmetries", description="Tuple of integers defining reflection symmetry across a plane " @@ -299,8 +313,8 @@ class HeatChargeSimulation(AbstractSimulation): analysis_spec: AnalysisSpecType = pd.Field( None, title="Analysis specification.", - description="The `analysis_spec` is used to validate that the simulation parameters and tolerance settings " - "are correctly configured as desired by the user.", + description="The `analysis_spec` is used to specify the type of simulation. Currently, it is used to " + "specify Charge simulations or transient Heat simulations.", ) @pd.validator("structures", always=True) @@ -315,7 +329,7 @@ def check_unsupported_geometries(cls, val): return val @staticmethod - def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: + def _check_cross_solids(objs: tuple[Box, ...], values: dict) -> tuple[int, ...]: """Given model dictionary ``values``, check whether objects in list ``objs`` cross a ``SolidSpec`` medium. """ @@ -335,7 +349,7 @@ def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: "'size', 'center', 'medium', and 'structures'. Thus, it should only be used in " "validators with @skip_if_fields_missing(['medium', 'center', 'size', 'structures']) " "or root validators with option 'skip_on_failure=True'." - ) + ) from None # list of structures including background as a Box() structure_bg = Structure( @@ -346,7 +360,7 @@ def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: medium=medium, ) - total_structures = [structure_bg] + list(structures) + total_structures = [structure_bg, *list(structures)] obj_do_not_cross_solid_idx = [] obj_do_not_cross_cond_idx = [] @@ -358,8 +372,7 @@ def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: isinstance(medium.heat_spec, SolidMedium) for medium in medium_set ) crosses_elec_spec = any( - any([isinstance(medium.charge, medium_i)] for medium_i in valid_electric_medium) - for medium in medium_set + isinstance(medium.charge, valid_electric_medium) for medium in medium_set ) else: # approximate check for volumetric objects based on bounding boxes @@ -372,10 +385,7 @@ def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: crosses_elec_spec = any( obj.intersects(structure.geometry) for structure in total_structures - if any( - [isinstance(structure.medium.charge, medium_i)] - for medium_i in valid_electric_medium - ) + if isinstance(structure.medium.charge, valid_electric_medium) ) if not crosses_solid: @@ -390,8 +400,8 @@ def _check_cross_solids(objs: Tuple[Box, ...], values: Dict) -> Tuple[int, ...]: def _monitors_cross_solids(cls, val, values): """Error if monitors does not cross any solid medium.""" - if val is None: - return val + # if val is None: + # return val failed_solid_idx, failed_elect_idx = cls._check_cross_solids(val, values) @@ -434,11 +444,8 @@ def check_voltage_array_if_capacitance(cls, values): for bc in bounday_spec: if isinstance(bc.condition, VoltageBC): if isinstance(bc.condition.source, DCVoltageSource): - if isinstance(bc.condition.source.voltage, list) or isinstance( - bc.condition.source.voltage, tuple - ): - if len(bc.condition.source.voltage) > 1: - voltage_array_present = True + if len(bc.condition.source.voltage) > 1: + voltage_array_present = True if is_capacitance_mnt and not voltage_array_present: raise SetupError( "Monitors of type 'SteadyCapacitanceMonitor' have been defined but no array of voltages " @@ -521,15 +528,14 @@ def check_only_one_voltage_array_provided(cls, val, values): if isinstance(bc.condition.source, DCVoltageSource): voltages = bc.condition.source.voltage - if isinstance(voltages, tuple): - if len(voltages) > 1: - if not array_already_provided: - array_already_provided = True - else: - raise SetupError( - "More than one voltage array has been provided. " - "Currently voltage arrays are supported only for one of the BCs." - ) + if len(voltages) > 1: + if not array_already_provided: + array_already_provided = True + else: + raise SetupError( + "More than one voltage array has been provided. " + "Currently voltage arrays are supported only for one of the BCs." + ) return val @pd.root_validator(skip_on_failure=True) @@ -722,7 +728,7 @@ def _check_if_semiconductor_present(structures) -> bool: @staticmethod def _check_simulation_types( - values: Dict, + values: dict, HeatBCTypes=HeatBCTypes, ElectricBCTypes=ElectricBCTypes, HeatSourceTypes=HeatSourceTypes, @@ -782,6 +788,55 @@ def check_coupling_source_can_be_applied(cls, values): return values + @pd.root_validator(skip_on_failure=True) + def check_heat_sim(cls, values): + """Make sure that heat simulations have at least one monitor defined.""" + + simulation_types = cls._check_simulation_types(values=values) + + if TCADAnalysisTypes.HEAT in simulation_types: + monitors = values.get("monitors") + if not any(isinstance(mnt, TemperatureMonitor) for mnt in monitors): + raise SetupError( + "Heat simulations require the definition of, at least, one " + "'TemperatureMonitor' but none have been defined." + ) + + return values + + @pd.root_validator(skip_on_failure=True) + def check_conduction_sim(cls, values): + """Make sure that conduction simulations have at least one monitor defined.""" + + simulation_types = cls._check_simulation_types(values=values) + sources = values.get("sources") + + if TCADAnalysisTypes.CONDUCTION in simulation_types: + monitors = values.get("monitors") + if not any(isinstance(mnt, SteadyPotentialMonitor) for mnt in monitors): + if any(isinstance(s, HeatFromElectricSource) for s in sources): + log.warning( + "A Conduction simulation has been defined but no " + "SteadyPotentialMonitor has been defined. " + ) + else: + raise SetupError( + "Conduction simulations require the definition of, at least, one " + "'SteadyPotentialMonitor' but none have been defined." + ) + + # now make sure we only have one voltage per VoltageBC + for bc in values.get("boundary_spec", []): + if isinstance(bc.condition, VoltageBC): + if isinstance(bc.condition.source, DCVoltageSource): + if len(bc.condition.source.voltage) > 1: + raise SetupError( + "A Conduction simulation has been defined but a VoltageBC with an array of voltages " + "has been defined. This is not supported in Conduction simulations." + ) + + return values + @pd.root_validator(skip_on_failure=True) def estimate_charge_mesh_size(cls, values): """Make an estimate of the mesh size and raise a warning if too big. @@ -834,20 +889,86 @@ def estimate_charge_mesh_size(cls, values): ) return values + @pd.root_validator(skip_on_failure=True) + def check_transient_heat(cls, values): + """Make sure transient heat simulations can run.""" + + analysis_type = values.get("analysis_spec") + if isinstance(analysis_type, UnsteadyHeatAnalysis): + monitors = values.get("monitors") + for mnt in monitors: + if isinstance(mnt, TemperatureMonitor): + if not mnt.unstructured: + raise SetupError( + f"Unsteady simulations require the temperature monitor '{mnt.name}' to be unstructured." + ) + # additionaly check that the SolidSpec has capacity and density defined + capacities = [] + densities = [] + conductivities = [] + structures = values.get("structures") + for structure in structures: + heat_properties = None + if isinstance(structure.medium, MultiPhysicsMedium): + heat_properties = structure.medium.heat + # now check legacy Medium too + elif isinstance(structure.medium, Medium): + heat_properties = structure.medium.heat_spec + + if isinstance(heat_properties, SolidMedium): + if heat_properties.capacity is not None: + capacities.append(heat_properties.capacity) + if heat_properties.density is not None: + densities.append(heat_properties.density) + conductivities.append(heat_properties.conductivity) + + if len(capacities) == 0 or len(densities) == 0 or len(conductivities) == 0: + raise SetupError( + "Unsteady simulations require the SolidSpec to have 'capacity', 'density', and 'conductivity' " + "defined. Please check the definition of the SolidSpec in the Medium or MultiPhysicsMedium." + ) + + # check that we don't have too many time-steps + if analysis_type.unsteady_spec.total_time_steps > TRANSIENT_HEAT_MAX_STEPS: + raise SetupError( + "Unsteady simulations require the number of time-steps to be less than " + f"{TRANSIENT_HEAT_MAX_STEPS} but {analysis_type.unsteady_spec.total_time_steps} were provided." + ) + + # check simulation time + domain_length = np.max([d for d in values.get("size") if d != np.inf]) + characteristic_time = ( + domain_length**2 + * np.mean(capacities) + * np.mean(densities) + / np.mean(conductivities) + * 1e-18 + ) + if ( + analysis_type.unsteady_spec.time_step * analysis_type.unsteady_spec.total_time_steps + > 100 * characteristic_time + ): + log.warning( + "The simulation time is larger than 100 times the estimated characteristic time of the system. " + "This may lead to unnecessary long simulation times. " + "Consider reducing the simulation time or the time step size." + ) + return values + @equal_aspect @add_ax_if_none def plot_property( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, property: str = "heat_conductivity", - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -937,16 +1058,16 @@ def plot_property( @add_ax_if_none def plot_heat_conductivity( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, colorbar: str = "conductivity", - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **kwargs, ) -> Ax: """ @@ -1012,9 +1133,9 @@ def plot_heat_conductivity( @add_ax_if_none def plot_boundaries( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, property: str = "heat_conductivity", ax: Ax = None, ) -> Ax: @@ -1043,7 +1164,7 @@ def plot_boundaries( # get structure list structures = [self.simulation_structure] - structures += list(self.structures) + structures += list(self.scene.sorted_structures) # construct slicing plane axis, position = Box.parse_xyz_kwargs(x=x, y=y, z=z) @@ -1107,9 +1228,9 @@ def _plot_boundary_condition( @staticmethod def _structure_to_bc_spec_map( plane: Box, - structures: Tuple[Structure, ...], - boundary_spec: Tuple[HeatChargeBoundarySpec, ...], - ) -> Dict[str, HeatChargeBoundarySpec]: + structures: tuple[Structure, ...], + boundary_spec: tuple[HeatChargeBoundarySpec, ...], + ) -> dict[str, HeatChargeBoundarySpec]: """Construct structure name to bc spec inverse mapping. One structure may correspond to multiple boundary conditions.""" @@ -1143,9 +1264,9 @@ def _structure_to_bc_spec_map( @staticmethod def _medium_to_bc_spec_map( plane: Box, - structures: Tuple[Structure, ...], - boundary_spec: Tuple[HeatChargeBoundarySpec, ...], - ) -> Dict[str, HeatChargeBoundarySpec]: + structures: tuple[Structure, ...], + boundary_spec: tuple[HeatChargeBoundarySpec, ...], + ) -> dict[str, HeatChargeBoundarySpec]: """Construct medium name to bc spec inverse mapping. One medium may correspond to multiple boundary conditions.""" @@ -1168,11 +1289,11 @@ def _medium_to_bc_spec_map( @staticmethod def _construct_forward_boundaries( - shapes: Tuple[Tuple[str, str, Shapely, Tuple[float, float, float, float]], ...], - struct_to_bc_spec: Dict[str, HeatChargeBoundarySpec], - med_to_bc_spec: Dict[str, HeatChargeBoundarySpec], + shapes: tuple[tuple[str, str, Shapely, tuple[float, float, float, float]], ...], + struct_to_bc_spec: dict[str, HeatChargeBoundarySpec], + med_to_bc_spec: dict[str, HeatChargeBoundarySpec], background_structure_shape: Shapely, - ) -> Tuple[Tuple[HeatChargeBoundarySpec, Shapely], ...]: + ) -> tuple[tuple[HeatChargeBoundarySpec, Shapely], ...]: """Construct Simulation, StructureSimulation, Structure, and MediumMedium boundaries.""" # forward foop to take care of Simulation, StructureSimulation, Structure, @@ -1260,10 +1381,10 @@ def _construct_forward_boundaries( @staticmethod def _construct_reverse_boundaries( - shapes: Tuple[Tuple[str, str, Shapely, Bound], ...], - struct_to_bc_spec: Dict[str, HeatChargeBoundarySpec], + shapes: tuple[tuple[str, str, Shapely, Bound], ...], + struct_to_bc_spec: dict[str, HeatChargeBoundarySpec], background_structure_shape: Shapely, - ) -> Tuple[Tuple[HeatChargeBoundarySpec, Shapely], ...]: + ) -> tuple[tuple[HeatChargeBoundarySpec, Shapely], ...]: """Construct StructureStructure boundaries.""" # backward foop to take care of StructureStructure @@ -1328,10 +1449,10 @@ def _construct_reverse_boundaries( @staticmethod def _construct_heat_charge_boundaries( - structures: List[Structure], + structures: list[Structure], plane: Box, - boundary_spec: List[HeatChargeBoundarySpec], - ) -> List[Tuple[HeatChargeBoundarySpec, Shapely]]: + boundary_spec: list[HeatChargeBoundarySpec], + ) -> list[tuple[HeatChargeBoundarySpec, Shapely]]: """Compute list of boundary lines to plot on plane. Parameters @@ -1395,13 +1516,13 @@ def _construct_heat_charge_boundaries( @add_ax_if_none def plot_sources( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, property: str = "heat_conductivity", - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, - alpha: float = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, + alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's sources on a plane defined by one nonzero x,y,z coordinate. @@ -1433,7 +1554,7 @@ def plot_sources( """ # background can't have source, so no need to add background structure - structures = self.structures + structures = self.scene.sorted_structures # alpha is None just means plot without any transparency if alpha is None: @@ -1498,28 +1619,16 @@ def _add_source_cbar(self, ax: Ax, property: str = "heat_conductivity"): ax=ax, ) - def _safe_float_conversion(self, string) -> float: - """Function to deal with failed string2float conversion when using - expressions in 'HeatSource'""" - try: - return float(string) - except ValueError: - return None - - def source_bounds(self, property: str = "heat_conductivity") -> Tuple[float, float]: + def source_bounds(self, property: str = "heat_conductivity") -> tuple[float, float]: """Compute range of heat sources present in the simulation.""" if property == "heat_conductivity" or property == "source": rate_list = [ - self._safe_float_conversion(source.rate) - for source in self.sources - if isinstance(source, HeatSource) + np.mean(source.rate) for source in self.sources if isinstance(source, HeatSource) ] elif property == "electric_conductivity": rate_list = [ - self._safe_float_conversion(source.rate) - for source in self.sources - if isinstance(source, ChargeSourceTypes) + source.rate for source in self.sources if isinstance(source, ChargeSourceTypes) ] # this is currently an empty list rate_list.append(0) @@ -1532,7 +1641,7 @@ def _get_structure_source_plot_params( source: HeatChargeSourceType, source_min: float, source_max: float, - alpha: float = None, + alpha: Optional[float] = None, ) -> PlotParams: """Constructs the plot parameters for a given medium in simulation.plot_eps().""" @@ -1541,7 +1650,7 @@ def _get_structure_source_plot_params( plot_params = plot_params.copy(update={"alpha": alpha}) if isinstance(source, HeatSource): - rate = self._safe_float_conversion(source.rate) + rate = np.mean(source.rate) if rate is not None: delta_rate = rate - source_min delta_rate_max = source_max - source_min + 1e-5 @@ -1559,7 +1668,7 @@ def _plot_shape_structure_source( source_min: float, source_max: float, ax: Ax, - alpha: float = None, + alpha: Optional[float] = None, ) -> Ax: """Plot a structure's cross section shape for a given medium, grayscale for permittivity.""" plot_params = self._get_structure_source_plot_params( @@ -1585,7 +1694,7 @@ def from_scene(cls, scene: Scene, **kwargs) -> HeatChargeSimulation: Example ------- - >>> from tidy3d import Scene, Medium, Box, Structure, UniformUnstructuredGrid + >>> from tidy3d import Scene, Medium, Box, Structure, UniformUnstructuredGrid, TemperatureMonitor >>> box = Structure( ... geometry=Box(center=(0, 0, 0), size=(1, 2, 3)), ... medium=Medium(permittivity=5), @@ -1611,6 +1720,7 @@ def from_scene(cls, scene: Scene, **kwargs) -> HeatChargeSimulation: ... condition=TemperatureBC(temperature=500), ... ) ... ], + ... monitors=[TemperatureMonitor(name="temp_monitor", center=(0, 0, 0), size=(1, 1, 1))], ... ) """ @@ -1629,8 +1739,13 @@ def _get_simulation_types(self) -> list[TCADAnalysisTypes]: # NOTE: for the time being, if a simulation has SemiconductorMedium # then we consider it of being a 'TCADAnalysisTypes.CHARGE' - if self._check_if_semiconductor_present(self.structures): - return [TCADAnalysisTypes.CHARGE] + if isinstance(self.analysis_spec, ElectricalAnalysisType): + if self._check_if_semiconductor_present(self.structures): + return [TCADAnalysisTypes.CHARGE] + + # check if unsteady heat + if isinstance(self.analysis_spec, UnsteadyHeatAnalysis): + return [TCADAnalysisTypes.HEAT] heat_source_present = any(isinstance(s, HeatSourceTypes) for s in self.sources) @@ -1638,7 +1753,7 @@ def _get_simulation_types(self) -> list[TCADAnalysisTypes]: if heat_source_present and not heat_BCs_present: raise SetupError("Heat sources defined but no heat BCs present.") - elif heat_BCs_present or heat_source_present: + if heat_BCs_present or heat_source_present: simulation_types.append(TCADAnalysisTypes.HEAT) # check for conduction simulation @@ -1657,7 +1772,7 @@ def _get_simulation_types(self) -> list[TCADAnalysisTypes]: "'.medium.charge=None' are treated as insulators, thus, " "the solution domain is empty." ) - elif electric_BCs_present and electric_spec_present: + if electric_BCs_present and electric_spec_present: simulation_types.append(TCADAnalysisTypes.CONDUCTION) return simulation_types diff --git a/tidy3d/components/tcad/source/abstract.py b/tidy3d/components/tcad/source/abstract.py index 9e1b7ffa71..d5891207e8 100644 --- a/tidy3d/components/tcad/source/abstract.py +++ b/tidy3d/components/tcad/source/abstract.py @@ -3,7 +3,6 @@ from __future__ import annotations from abc import ABC -from typing import Tuple import pydantic.v1 as pd @@ -28,7 +27,7 @@ class StructureBasedHeatChargeSource(AbstractHeatChargeSource): """Abstract class associated with structures. Sources associated to structures must derive from this class""" - structures: Tuple[str, ...] = pd.Field( + structures: tuple[str, ...] = pd.Field( title="Target Structures", description="Names of structures where to apply heat source.", ) diff --git a/tidy3d/components/tcad/source/heat.py b/tidy3d/components/tcad/source/heat.py index ba269d31ad..8d7c6ea633 100644 --- a/tidy3d/components/tcad/source/heat.py +++ b/tidy3d/components/tcad/source/heat.py @@ -6,6 +6,7 @@ import pydantic.v1 as pd +from tidy3d.components.data.data_array import SpatialDataArray from tidy3d.components.tcad.source.abstract import StructureBasedHeatChargeSource from tidy3d.constants import VOLUMETRIC_HEAT_RATE from tidy3d.log import log @@ -20,7 +21,7 @@ class HeatSource(StructureBasedHeatChargeSource): >>> heat_source = HeatSource(rate=1, structures=["box"]) """ - rate: Union[float] = pd.Field( + rate: Union[float, SpatialDataArray] = pd.Field( title="Volumetric Heat Rate", description="Volumetric rate of heating or cooling (if negative) in units of " f"{VOLUMETRIC_HEAT_RATE}.", diff --git a/tidy3d/components/tcad/types.py b/tidy3d/components/tcad/types.py index c3520d8a86..dec3f44f62 100644 --- a/tidy3d/components/tcad/types.py +++ b/tidy3d/components/tcad/types.py @@ -1,5 +1,7 @@ """File containing classes required for the setup of a DEVSIM case.""" +from __future__ import annotations + from tidy3d.components.tcad.bandgap import SlotboomBandGapNarrowing from tidy3d.components.tcad.boundary.charge import CurrentBC, InsulatingBC, VoltageBC from tidy3d.components.tcad.boundary.heat import ConvectionBC, HeatFluxBC, TemperatureBC @@ -11,6 +13,7 @@ from tidy3d.components.tcad.mobility import CaugheyThomasMobility, ConstantMobilityModel from tidy3d.components.tcad.monitors.charge import ( SteadyCapacitanceMonitor, + SteadyElectricFieldMonitor, SteadyEnergyBandMonitor, SteadyFreeCarrierMonitor, SteadyPotentialMonitor, @@ -32,6 +35,7 @@ SteadyPotentialMonitor, SteadyFreeCarrierMonitor, SteadyEnergyBandMonitor, + SteadyElectricFieldMonitor, SteadyCapacitanceMonitor, ] HeatChargeSourceType = Union[HeatSource, HeatFromElectricSource, UniformHeatSource] diff --git a/tidy3d/components/tcad/viz.py b/tidy3d/components/tcad/viz.py index 4de6fd825b..e305e0c317 100644 --- a/tidy3d/components/tcad/viz.py +++ b/tidy3d/components/tcad/viz.py @@ -1,5 +1,7 @@ """utilities for heat solver plotting""" +from __future__ import annotations + from tidy3d.components.viz import PlotParams """ Constants """ diff --git a/tidy3d/components/time.py b/tidy3d/components/time.py index c26ebf88ba..93bd91bd91 100644 --- a/tidy3d/components/time.py +++ b/tidy3d/components/time.py @@ -7,8 +7,9 @@ import numpy as np import pydantic.v1 as pydantic -from ..constants import RADIAN -from ..exceptions import SetupError +from tidy3d.constants import RADIAN +from tidy3d.exceptions import SetupError + from .base import Tidy3dBaseModel from .types import ArrayFloat1D, Ax, PlotVal from .viz import add_ax_if_none diff --git a/tidy3d/components/time_modulation.py b/tidy3d/components/time_modulation.py index 93b55cee6b..a4d82d7384 100644 --- a/tidy3d/components/time_modulation.py +++ b/tidy3d/components/time_modulation.py @@ -9,8 +9,9 @@ import numpy as np import pydantic.v1 as pd -from ..constants import HERTZ, RADIAN -from ..exceptions import ValidationError +from tidy3d.constants import HERTZ, RADIAN +from tidy3d.exceptions import ValidationError + from .base import Tidy3dBaseModel, cached_property, skip_if_fields_missing from .data.data_array import SpatialDataArray from .data.validators import validate_no_nans diff --git a/tidy3d/components/transformation.py b/tidy3d/components/transformation.py index ea7c1ee494..4e2643a9ae 100644 --- a/tidy3d/components/transformation.py +++ b/tidy3d/components/transformation.py @@ -8,8 +8,9 @@ import numpy as np import pydantic.v1 as pd -from ..constants import RADIAN -from ..exceptions import ValidationError +from tidy3d.constants import RADIAN +from tidy3d.exceptions import ValidationError + from .autograd import TracedFloat from .base import Tidy3dBaseModel, cached_property from .types import ArrayFloat2D, Axis, Coordinate, TensorReal diff --git a/tidy3d/components/type_util.py b/tidy3d/components/type_util.py index 5bbb64f975..983f623829 100644 --- a/tidy3d/components/type_util.py +++ b/tidy3d/components/type_util.py @@ -1,5 +1,7 @@ """Utilities for type & schema creation.""" +from __future__ import annotations + def _add_schema(arbitrary_type: type, title: str, field_type_str: str) -> None: """Adds a schema to the ``arbitrary_type`` class without subclassing.""" @@ -7,6 +9,6 @@ def _add_schema(arbitrary_type: type, title: str, field_type_str: str) -> None: @classmethod def mod_schema_fn(cls, field_schema: dict) -> None: """Function that gets set to ``arbitrary_type.__modify_schema__``.""" - field_schema.update(dict(title=title, type=field_type_str)) + field_schema.update({"title": title, "type": field_type_str}) arbitrary_type.__modify_schema__ = mod_schema_fn diff --git a/tidy3d/components/types.py b/tidy3d/components/types.py index 61697f87d4..0489d56797 100644 --- a/tidy3d/components/types.py +++ b/tidy3d/components/types.py @@ -1,11 +1,8 @@ """Defines 'types' that various fields can be""" -from typing import ( - Literal, # We support py3.9+, so direct typing import is fine. - Optional, - Tuple, - Union, -) +from __future__ import annotations + +from typing import Literal, Optional, Union import autograd.numpy as np import pydantic.v1 as pydantic @@ -14,10 +11,11 @@ from matplotlib.axes import Axes except ImportError: Axes = None +from typing import Annotated + from shapely.geometry.base import BaseGeometry -from typing_extensions import Annotated -from ..exceptions import ValidationError +from tidy3d.exceptions import ValidationError # type tag default name TYPE_TAG_STR = "type" @@ -99,14 +97,16 @@ def assert_non_null(cls, val): def __modify_schema__(cls, field_schema): """Sets the schema of DataArray object.""" - schema = dict( - type="ArrayLike", - ) + schema = { + "type": "ArrayLike", + } field_schema.update(schema) def constrained_array( - dtype: type = None, ndim: int = None, shape: Tuple[pydantic.NonNegativeInt, ...] = None + dtype: Optional[type] = None, + ndim: Optional[int] = None, + shape: Optional[tuple[pydantic.NonNegativeInt, ...]] = None, ) -> type: """Generate an ArrayLike sub-type with constraints built in.""" @@ -122,7 +122,7 @@ def constrained_array( meta_args.append(f"shape={shape}") type_name += "[" + ", ".join(meta_args) + "]" - return type(type_name, (ArrayLike,), dict(dtype=dtype, ndim=ndim, shape=shape)) + return type(type_name, (ArrayLike,), {"dtype": dtype, "ndim": ndim, "shape": shape}) # pre-define a set of commonly used array like instances for import and use in type hints @@ -187,12 +187,12 @@ def __modify_schema__(cls, field_schema): """ geometric """ Size1D = pydantic.NonNegativeFloat -Size = Tuple[Size1D, Size1D, Size1D] -Coordinate = Tuple[float, float, float] -CoordinateOptional = Tuple[Optional[float], Optional[float], Optional[float]] -Coordinate2D = Tuple[float, float] -Bound = Tuple[Coordinate, Coordinate] -GridSize = Union[pydantic.PositiveFloat, Tuple[pydantic.PositiveFloat, ...]] +Size = tuple[Size1D, Size1D, Size1D] +Coordinate = tuple[float, float, float] +CoordinateOptional = tuple[Optional[float], Optional[float], Optional[float]] +Coordinate2D = tuple[float, float] +Bound = tuple[Coordinate, Coordinate] +GridSize = Union[pydantic.PositiveFloat, tuple[pydantic.PositiveFloat, ...]] Axis = Literal[0, 1, 2] Axis2D = Literal[0, 1] Shapely = BaseGeometry @@ -200,6 +200,7 @@ def __modify_schema__(cls, field_schema): ClipOperationType = Literal["union", "intersection", "difference", "symmetric_difference"] BoxSurface = Literal["x-", "x+", "y-", "y+", "z-", "z+"] LengthUnit = Literal["nm", "μm", "um", "mm", "cm", "m"] +PriorityMode = Literal["equal", "conductor"] """ medium """ @@ -208,12 +209,12 @@ def __modify_schema__(cls, field_schema): # Complex = Union[complex, ComplexNumber] Complex = Union[tidycomplex, ComplexNumber] -PoleAndResidue = Tuple[Complex, Complex] +PoleAndResidue = tuple[Complex, Complex] # PoleAndResidue = Tuple[Tuple[float, float], Tuple[float, float]] FreqBoundMax = float FreqBoundMin = float -FreqBound = Tuple[FreqBoundMin, FreqBoundMax] +FreqBound = tuple[FreqBoundMin, FreqBoundMax] PermittivityComponent = Literal["xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz"] @@ -226,8 +227,8 @@ def __modify_schema__(cls, field_schema): EMField = Literal["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"] FieldType = Literal["Ex", "Ey", "Ez", "Hx", "Hy", "Hz"] -FreqArray = Union[Tuple[float, ...], ArrayFloat1D] -ObsGridArray = Union[Tuple[float, ...], ArrayFloat1D] +FreqArray = Union[tuple[float, ...], ArrayFloat1D] +ObsGridArray = Union[tuple[float, ...], ArrayFloat1D] PolarizationBasis = Literal["linear", "circular"] AuxField = Literal["Nfx", "Nfy", "Nfz"] @@ -257,3 +258,6 @@ def __modify_schema__(cls, field_schema): xyz = Literal["x", "y", "z"] UnitsZBF = Literal["mm", "cm", "in", "m"] + +""" sentinel """ +Undefined = object() diff --git a/tidy3d/components/types_extra.py b/tidy3d/components/types_extra.py index 92a6342ade..4fe305ce68 100644 --- a/tidy3d/components/types_extra.py +++ b/tidy3d/components/types_extra.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from typing import Any -from ..packaging import check_import +from tidy3d.packaging import check_import # TODO Complicated as trimesh should be a core package unless decoupled implementation types in functional location. # We need to restructure. diff --git a/tidy3d/components/validators.py b/tidy3d/components/validators.py index 55bca5575e..9e51081fe7 100644 --- a/tidy3d/components/validators.py +++ b/tidy3d/components/validators.py @@ -1,17 +1,20 @@ """Defines various validation functions that get used to ensure inputs are legit""" +from __future__ import annotations + +from typing import Any, Optional + import numpy as np import pydantic.v1 as pydantic from autograd.tracer import isbox -from ..exceptions import SetupError, ValidationError -from ..log import log +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log + from .autograd.utils import get_static from .base import DATA_ARRAY_MAP, skip_if_fields_missing from .data.dataset import Dataset, FieldDataset from .geometry.base import Box -from .mode_spec import ModeSpec -from .types import Tuple """ Explanation of pydantic validators: @@ -49,6 +52,14 @@ MIN_FREQUENCY = 1e5 +def named_obj_descr(obj: Any, field_name: str, position_index: int) -> str: + """Generate a string describing a named object which can be used in error messages.""" + descr = f"simulation.{field_name}[{position_index}] (no `name` was specified)" + if hasattr(obj, "name") and obj.name: + descr = f"'{obj.name}' (simulation.{field_name}[{position_index}])" + return descr + + def assert_line(): """makes sure a field's ``size`` attribute has exactly 2 zeros""" @@ -153,10 +164,10 @@ def check_symmetry(cls, val, values): and bounds_min[dim] < sim_center[dim] and geometric_object.center[dim] != sim_center[dim] ): + obj_descr = named_obj_descr(geometric_object, field_name, position_index) raise SetupError( - f"{obj_type} at 'simulation.{field_name}[{position_index}]' " - "in presence of symmetries must be in the main quadrant, " - "or centered on the symmetry axis." + f"{obj_type}: {obj_descr} in presence of symmetries must be in the main " + "quadrant, or centered on the symmetry axis." ) return val @@ -198,12 +209,9 @@ def objects_in_sim_bounds(cls, val, values): with log as consolidated_logger: for position_index, geometric_object in enumerate(val): if not sim_box.intersects(geometric_object.geometry, strict_inequality=strict_ineq): - message = ( - f"'simulation.{field_name}[{position_index}]' " - "is outside of the simulation domain." - ) + obj_descr = named_obj_descr(geometric_object, field_name, position_index) + message = f"{obj_descr} is outside of the simulation domain." custom_loc = [field_name, position_index] - if error: raise SetupError(message) consolidated_logger.warning(message, custom_loc=custom_loc) @@ -214,7 +222,10 @@ def objects_in_sim_bounds(cls, val, values): def assert_objects_contained_in_sim_bounds( - field_name: str, error: bool = True, strict_inequality: bool = False + field_name: str, + error: bool = True, + strict_inequality: bool = False, + strict_for_zero_size_dim: bool = False, ): """Makes sure all objects in field are completely inside the simulation bounds.""" @@ -228,16 +239,20 @@ def objects_contained_in_sim_bounds(cls, val, values): # Do a strict check, unless simulation is 0D along a dimension strict_ineq = [size != 0 and strict_inequality for size in sim_size] - with log as consolidated_logger: for position_index, geometric_object in enumerate(val): - if not sim_box.contains(geometric_object.geometry, strict_inequality=strict_ineq): - message = ( - f"'simulation.{field_name}[{position_index}]' " - "is not completely inside the simulation domain." - ) + geo_strict_ineq = list(strict_ineq) + # Optionally ensure that zero size dimensions are strictly contained + if strict_for_zero_size_dim: + zero_dims = geometric_object.geometry.zero_dims + for zero_dim in zero_dims: + geo_strict_ineq[zero_dim] = True + if not sim_box.contains( + geometric_object.geometry, strict_inequality=geo_strict_ineq + ): + obj_descr = named_obj_descr(geometric_object, field_name, position_index) + message = f"{obj_descr} is not completely inside the simulation domain." custom_loc = [field_name, position_index] - if error: raise SetupError(message) consolidated_logger.warning(message, custom_loc=custom_loc) @@ -323,9 +338,9 @@ def _single_frequency_in_range(cls, val: FieldDataset, values: dict) -> FieldDat def _warn_potential_error( field_name: str, base_value: float, - val_change_range: Tuple[float, float], - allowed_real_range: Tuple[float, float], - allowed_imag_range: Tuple[float, float], + val_change_range: tuple[float, float], + allowed_real_range: tuple[float, float], + allowed_imag_range: tuple[float, float], ): """Basic validation that perturbations do not drive a parameter out of physical bounds.""" @@ -358,8 +373,8 @@ def _warn_potential_error( def validate_parameter_perturbation( field_name: str, base_field_name: str, - allowed_real_range: Tuple[Tuple[float, float], ...], - allowed_imag_range: Tuple[Tuple[float, float], ...] = None, + allowed_real_range: tuple[tuple[float, float], ...], + allowed_imag_range: Optional[tuple[tuple[float, float], ...]] = None, allowed_complex: bool = True, ): """Assert perturbations do not drive a parameter out of physical bounds.""" @@ -450,24 +465,6 @@ def freqs_not_empty(cls, val): return freqs_not_empty -def validate_mode_plane_radius(mode_spec: ModeSpec, plane: Box, msg_prefix: str = ""): - """Validate that the radius of a mode spec with a bend is not smaller than half the size of - the plane along the radial direction.""" - - if not mode_spec.bend_radius: - return - - # radial axis is the plane axis that is not the bend axis - _, plane_axs = plane.pop_axis([0, 1, 2], plane.size.index(0.0)) - radial_ax = plane_axs[(mode_spec.bend_axis + 1) % 2] - - if np.abs(mode_spec.bend_radius) < plane.size[radial_ax] / 2: - raise ValueError( - f"{msg_prefix} bend radius is smaller than half the mode plane size " - "along the radial axis, which can produce wrong results." - ) - - def _warn_unsupported_traced_argument(name: str): @pydantic.validator(name, always=True, allow_reuse=True) def _warn_traced_arg(cls, val, values): diff --git a/tidy3d/components/viz.py b/tidy3d/components/viz.py deleted file mode 100644 index 55a1ce0243..0000000000 --- a/tidy3d/components/viz.py +++ /dev/null @@ -1,472 +0,0 @@ -"""utilities for plotting""" - -from __future__ import annotations - -from functools import wraps -from html import escape -from typing import Any, Dict, Optional - -import pydantic.v1 as pd - -try: - import matplotlib.pyplot as plt - import matplotlib.ticker as ticker - from matplotlib.colors import is_color_like - from matplotlib.patches import ArrowStyle, PathPatch - from matplotlib.path import Path - - # default arrow style - arrow_style = ArrowStyle.Simple(head_length=12, head_width=9, tail_width=4) -except ImportError: - arrow_style = None - -from numpy import array, concatenate, inf, ones - -from ..constants import UnitScaling -from ..exceptions import SetupError, Tidy3dKeyError -from .base import Tidy3dBaseModel -from .types import Ax, Axis, LengthUnit - -""" Constants """ - -# add this around extents of plots -PLOT_BUFFER = 0.3 - -ARROW_COLOR_MONITOR = "orange" -ARROW_COLOR_SOURCE = "green" -ARROW_COLOR_POLARIZATION = "brown" -ARROW_ALPHA = 0.8 - -# Arrow length in inches -ARROW_LENGTH = 0.3 - -FLEXCOMPUTE_COLORS = { - "brand_green": 0x00643C, - "brand_tan": 0xB8A18B, - "brand_blue": 0x6DB5DD, - "brand_purple": 0x8851AD, - "brand_black": 0x000000, -} - -""" Decorators """ - - -def make_ax() -> Ax: - """makes an empty ``ax``.""" - _, ax = plt.subplots(1, 1, tight_layout=True) - return ax - - -def add_ax_if_none(plot): - """Decorates ``plot(*args, **kwargs, ax=None)`` function. - if ax=None in the function call, creates an ax and feeds it to rest of function. - """ - - @wraps(plot) - def _plot(*args, **kwargs) -> Ax: - """New plot function using a generated ax if None.""" - if kwargs.get("ax") is None: - ax = make_ax() - kwargs["ax"] = ax - return plot(*args, **kwargs) - - return _plot - - -def equal_aspect(plot): - """Decorates a plotting function returning a matplotlib axes. - Ensures the aspect ratio of the returned axes is set to equal. - Useful for 2D plots, like sim.plot() or sim_data.plot_fields() - """ - - @wraps(plot) - def _plot(*args, **kwargs) -> Ax: - """New plot function with equal aspect ratio axes returned.""" - ax = plot(*args, **kwargs) - ax.set_aspect("equal") - return ax - - return _plot - - -""" plot parameters """ - - -class AbstractPlotParams(Tidy3dBaseModel): - """Abstract class for storing plotting parameters. - Corresponds with select properties of ``matplotlib.artist.Artist``. - """ - - alpha: Any = pd.Field(1.0, title="Opacity") - zorder: float = pd.Field(None, title="Display Order") - - def include_kwargs(self, **kwargs) -> AbstractPlotParams: - """Update the plot params with supplied kwargs.""" - update_dict = { - key: value - for key, value in kwargs.items() - if key not in ("type",) and value is not None and key in self.__fields__ - } - return self.copy(update=update_dict) - - def override_with_viz_spec(self, viz_spec) -> AbstractPlotParams: - """Override plot params with supplied VisualizationSpec.""" - return self.include_kwargs(**dict(viz_spec)) - - def to_kwargs(self) -> dict: - """Export the plot parameters as kwargs dict that can be supplied to plot function.""" - kwarg_dict = self.dict() - for ignore_key in ("type", "attrs"): - kwarg_dict.pop(ignore_key) - return kwarg_dict - - -class PathPlotParams(AbstractPlotParams): - """Stores plotting parameters / specifications for a path. - Corresponds with select properties of ``matplotlib.lines.Line2D``. - """ - - color: Any = pd.Field(None, title="Color", alias="c") - linewidth: pd.NonNegativeFloat = pd.Field(2, title="Line Width", alias="lw") - linestyle: str = pd.Field("--", title="Line Style", alias="ls") - marker: Any = pd.Field("o", title="Marker Style") - markeredgecolor: Any = pd.Field(None, title="Marker Edge Color", alias="mec") - markerfacecolor: Any = pd.Field(None, title="Marker Face Color", alias="mfc") - markersize: pd.NonNegativeFloat = pd.Field(10, title="Marker Size", alias="ms") - - -class PlotParams(AbstractPlotParams): - """Stores plotting parameters / specifications for a given model. - Corresponds with select properties of ``matplotlib.patches.Patch``. - """ - - edgecolor: Any = pd.Field(None, title="Edge Color", alias="ec") - facecolor: Any = pd.Field(None, title="Face Color", alias="fc") - fill: bool = pd.Field(True, title="Is Filled") - hatch: str = pd.Field(None, title="Hatch Style") - linewidth: pd.NonNegativeFloat = pd.Field(1, title="Line Width", alias="lw") - - -# defaults for different tidy3d objects -plot_params_geometry = PlotParams() -plot_params_structure = PlotParams() -plot_params_source = PlotParams(alpha=0.4, facecolor="limegreen", edgecolor="limegreen", lw=3) -plot_params_monitor = PlotParams(alpha=0.4, facecolor="orange", edgecolor="orange", lw=3) -plot_params_pml = PlotParams(alpha=0.7, facecolor="gray", edgecolor="gray", hatch="x", zorder=inf) -plot_params_pec = PlotParams(alpha=1.0, facecolor="gold", edgecolor="black", zorder=inf) -plot_params_pmc = PlotParams(alpha=1.0, facecolor="lightsteelblue", edgecolor="black", zorder=inf) -plot_params_bloch = PlotParams(alpha=1.0, facecolor="orchid", edgecolor="black", zorder=inf) -plot_params_symmetry = PlotParams(edgecolor="gray", facecolor="gray", alpha=0.6, zorder=inf) -plot_params_override_structures = PlotParams( - linewidth=0.4, edgecolor="black", fill=False, zorder=inf -) -plot_params_fluid = PlotParams(facecolor="white", edgecolor="lightsteelblue", lw=0.4, hatch="xx") -plot_params_grid = PlotParams(edgecolor="black", lw=0.2) -plot_params_lumped_element = PlotParams( - alpha=0.4, facecolor="mediumblue", edgecolor="mediumblue", lw=3 -) - -# stores color of simulation.structures for given index in simulation.medium_map -MEDIUM_CMAP = [ - "#689DBC", - "#D0698E", - "#5E6EAD", - "#C6224E", - "#BDB3E2", - "#9EC3E0", - "#616161", - "#877EBC", -] - -# colormap for structure's permittivity in plot_eps -STRUCTURE_EPS_CMAP = "gist_yarg" -STRUCTURE_EPS_CMAP_R = "gist_yarg_r" -STRUCTURE_HEAT_COND_CMAP = "gist_yarg" - - -def is_valid_color(value: str) -> str: - if not is_color_like(value): - raise pd.ValidationError(f"{value} is not a valid plotting color") - - return value - - -class VisualizationSpec(Tidy3dBaseModel): - """Defines specification for visualization when used with plotting functions.""" - - facecolor: str = pd.Field( - "", - title="Face color", - description="Color applied to the faces in visualization.", - ) - - edgecolor: Optional[str] = pd.Field( - "", - title="Edge color", - description="Color applied to the edges in visualization.", - ) - - alpha: Optional[pd.confloat(ge=0.0, le=1.0)] = pd.Field( - 1.0, - title="Opacity", - description="Opacity/alpha value in plotting between 0 and 1.", - ) - - @pd.validator("facecolor", always=True) - def validate_color(value: str) -> str: - return is_valid_color(value) - - @pd.validator("edgecolor", always=True) - def validate_and_copy_color(value: str, values: Dict[str, Any]) -> str: - if (value == "") and "facecolor" in values: - return is_valid_color(values["facecolor"]) - - return is_valid_color(value) - - -"""================================================================================================= -Descartes modified from https://pypi.org/project/descartes/ for Shapely >= 1.8.0 - -Copyright Flexcompute 2022 - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" - - -class Polygon: - """Adapt Shapely polygons to a common interface""" - - def __init__(self, context): - if isinstance(context, dict): - self.context = context["coordinates"] - else: - self.context = context - - @property - def exterior(self): - """Get polygon exterior.""" - return getattr(self.context, "exterior", None) or self.context[0] - - @property - def interiors(self): - """Get polygon interiors.""" - value = getattr(self.context, "interiors", None) - if value is None: - value = self.context[1:] - return value - - -def polygon_path(polygon): - """Constructs a compound matplotlib path from a Shapely or GeoJSON-like - geometric object""" - - def coding(obj): - # The codes will be all "LINETO" commands, except for "MOVETO"s at the - # beginning of each subpath - n = len(getattr(obj, "coords", None) or obj) - vals = ones(n, dtype=Path.code_type) * Path.LINETO - vals[0] = Path.MOVETO - return vals - - ptype = polygon.geom_type - if ptype == "Polygon": - polygon = [Polygon(polygon)] - elif ptype == "MultiPolygon": - polygon = [Polygon(p) for p in polygon.geoms] - - vertices = concatenate( - [ - concatenate( - [array(t.exterior.coords)[:, :2]] + [array(r.coords)[:, :2] for r in t.interiors] - ) - for t in polygon - ] - ) - codes = concatenate( - [concatenate([coding(t.exterior)] + [coding(r) for r in t.interiors]) for t in polygon] - ) - - return Path(vertices, codes) - - -def polygon_patch(polygon, **kwargs): - """Constructs a matplotlib patch from a geometric object - - The ``polygon`` may be a Shapely or GeoJSON-like object with or without holes. - The ``kwargs`` are those supported by the matplotlib.patches.Polygon class - constructor. Returns an instance of matplotlib.patches.PathPatch. - - Example - ------- - >>> b = Point(0, 0).buffer(1.0) # doctest: +SKIP - >>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5) # doctest: +SKIP - >>> axis.add_patch(patch) # doctest: +SKIP - - """ - return PathPatch(polygon_path(polygon), **kwargs) - - -"""End descartes modification -=================================================================================================""" - - -def plot_sim_3d(sim, width=800, height=800) -> None: - """Make 3D display of simulation in ipyython notebook.""" - - try: - from IPython.display import HTML, display - except ImportError as e: - raise SetupError( - "3D plotting requires ipython to be installed " - "and the code to be running on a jupyter notebook." - ) from e - - from base64 import b64encode - from io import BytesIO - - buffer = BytesIO() - sim.to_hdf5_gz(buffer) - buffer.seek(0) - base64 = b64encode(buffer.read()).decode("utf-8") - js_code = """ - /** - * Simulation Viewer Injector - * - * Monitors the document for elements being added in the form: - * - *
- * - * This script will then inject an iframe to the viewer application, and pass it the simulation data - * via the postMessage API on request. The script may be safely included multiple times, with only the - * configuration of the first started script (e.g. viewer URL) applying. - * - */ - (function() { - const TARGET_CLASS = "simulation-viewer"; - const ACTIVE_CLASS = "simulation-viewer-active"; - const VIEWER_URL = "https://tidy3d.simulation.cloud/simulation-viewer"; - - class SimulationViewerInjector { - constructor() { - for (var node of document.getElementsByClassName(TARGET_CLASS)) { - this.injectViewer(node); - } - - // Monitor for newly added nodes to the DOM - this.observer = new MutationObserver(this.onMutations.bind(this)); - this.observer.observe(document.body, {childList: true, subtree: true}); - } - - onMutations(mutations) { - for (var mutation of mutations) { - if (mutation.type === 'childList') { - /** - * Have found that adding the element does not reliably trigger the mutation observer. - * It may be the case that setting content with innerHTML does not trigger. - * - * It seems to be sufficient to re-scan the document for un-activated viewers - * whenever an event occurs, as Jupyter triggers multiple events on cell evaluation. - */ - var viewers = document.getElementsByClassName(TARGET_CLASS); - for (var node of viewers) { - this.injectViewer(node); - } - } - } - } - - injectViewer(node) { - // (re-)check that this is a valid simulation container and has not already been injected - if (node.classList.contains(TARGET_CLASS) && !node.classList.contains(ACTIVE_CLASS)) { - // Mark node as injected, to prevent re-runs - node.classList.add(ACTIVE_CLASS); - - var uuid; - if (window.crypto && window.crypto.randomUUID) { - uuid = window.crypto.randomUUID(); - } else { - uuid = "" + Math.random(); - } - - var frame = document.createElement("iframe"); - frame.width = node.dataset.width || 800; - frame.height = node.dataset.height || 800; - frame.style.cssText = `width:${frame.width}px;height:${frame.height}px;max-width:none;border:0;display:block` - frame.src = VIEWER_URL + "?uuid=" + uuid; - - var postMessageToViewer; - postMessageToViewer = event => { - if(event.data.type === 'viewer' && event.data.uuid===uuid){ - frame.contentWindow.postMessage({ type: 'jupyter', uuid, value: node.dataset.simulation, fileType: 'hdf5'}, '*'); - - // Run once only - window.removeEventListener('message', postMessageToViewer); - } - }; - window.addEventListener( - 'message', - postMessageToViewer, - false - ); - - node.appendChild(frame); - } - } - } - - if (!window.simulationViewerInjector) { - window.simulationViewerInjector = new SimulationViewerInjector(); - } - })(); - """ - html_code = f""" -
- - """ - - return display(HTML(html_code)) - - -def set_default_labels_and_title( - axis_labels: tuple[str, str], - axis: Axis, - position: float, - ax: Ax, - plot_length_units: LengthUnit = None, -) -> Ax: - """Adds axis labels and title to plots involving spatial dimensions. - When the ``plot_length_units`` are specified, the plot axes are scaled, and - the title and axis labels include the desired units. - """ - xlabel = axis_labels[0] - ylabel = axis_labels[1] - if plot_length_units is not None: - if plot_length_units not in UnitScaling: - raise Tidy3dKeyError( - f"Provided units '{plot_length_units}' are not supported. " - f"Please choose one of '{LengthUnit}'." - ) - ax.set_xlabel(f"{xlabel} ({plot_length_units})") - ax.set_ylabel(f"{ylabel} ({plot_length_units})") - # Formatter to help plot in arbitrary units - scale_factor = UnitScaling[plot_length_units] - formatter = ticker.FuncFormatter(lambda y, _: f"{y * scale_factor:.2f}") - ax.xaxis.set_major_formatter(formatter) - ax.yaxis.set_major_formatter(formatter) - ax.set_title( - f"cross section at {'xyz'[axis]}={position * scale_factor:.2f} ({plot_length_units})" - ) - else: - ax.set_xlabel(xlabel) - ax.set_ylabel(ylabel) - ax.set_title(f"cross section at {'xyz'[axis]}={position:.2f}") - return ax diff --git a/tidy3d/components/viz/__init__.py b/tidy3d/components/viz/__init__.py new file mode 100644 index 0000000000..1f3b5fb2ca --- /dev/null +++ b/tidy3d/components/viz/__init__.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from .axes_utils import add_ax_if_none, equal_aspect, make_ax, set_default_labels_and_title +from .descartes import Polygon, polygon_patch, polygon_path +from .flex_style import apply_tidy3d_params, restore_matplotlib_rcparams +from .plot_params import ( + AbstractPlotParams, + PathPlotParams, + PlotParams, + plot_params_bloch, + plot_params_fluid, + plot_params_geometry, + plot_params_grid, + plot_params_lumped_element, + plot_params_monitor, + plot_params_override_structures, + plot_params_pec, + plot_params_pmc, + plot_params_pml, + plot_params_source, + plot_params_structure, + plot_params_symmetry, +) +from .plot_sim_3d import plot_sim_3d +from .styles import ( + ARROW_ALPHA, + ARROW_COLOR_MONITOR, + ARROW_COLOR_POLARIZATION, + ARROW_COLOR_SOURCE, + ARROW_LENGTH, + FLEXCOMPUTE_COLORS, + MEDIUM_CMAP, + PLOT_BUFFER, + STRUCTURE_EPS_CMAP, + STRUCTURE_EPS_CMAP_R, + STRUCTURE_HEAT_COND_CMAP, + arrow_style, +) +from .visualization_spec import MATPLOTLIB_IMPORTED, VisualizationSpec + +apply_tidy3d_params() + +__all__ = [ + "ARROW_ALPHA", + "ARROW_COLOR_MONITOR", + "ARROW_COLOR_POLARIZATION", + "ARROW_COLOR_SOURCE", + "ARROW_LENGTH", + "FLEXCOMPUTE_COLORS", + "MATPLOTLIB_IMPORTED", + "MEDIUM_CMAP", + "PLOT_BUFFER", + "STRUCTURE_EPS_CMAP", + "STRUCTURE_EPS_CMAP_R", + "STRUCTURE_HEAT_COND_CMAP", + "AbstractPlotParams", + "PathPlotParams", + "PlotParams", + "Polygon", + "VisualizationSpec", + "add_ax_if_none", + "arrow_style", + "equal_aspect", + "make_ax", + "plot_params_bloch", + "plot_params_fluid", + "plot_params_geometry", + "plot_params_grid", + "plot_params_lumped_element", + "plot_params_monitor", + "plot_params_override_structures", + "plot_params_pec", + "plot_params_pmc", + "plot_params_pml", + "plot_params_source", + "plot_params_structure", + "plot_params_symmetry", + "plot_sim_3d", + "polygon_patch", + "polygon_path", + "restore_matplotlib_rcparams", + "set_default_labels_and_title", +] diff --git a/tidy3d/components/viz/axes_utils.py b/tidy3d/components/viz/axes_utils.py new file mode 100644 index 0000000000..14f1aa3cab --- /dev/null +++ b/tidy3d/components/viz/axes_utils.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from functools import wraps +from typing import Optional + +from tidy3d.components.types import Ax, Axis, LengthUnit +from tidy3d.constants import UnitScaling +from tidy3d.exceptions import Tidy3dKeyError + + +def make_ax() -> Ax: + """makes an empty ``ax``.""" + import matplotlib.pyplot as plt + + _, ax = plt.subplots(1, 1, tight_layout=True) + return ax + + +def add_ax_if_none(plot): + """Decorates ``plot(*args, **kwargs, ax=None)`` function. + if ax=None in the function call, creates an ax and feeds it to rest of function. + """ + + @wraps(plot) + def _plot(*args, **kwargs) -> Ax: + """New plot function using a generated ax if None.""" + if kwargs.get("ax") is None: + ax = make_ax() + kwargs["ax"] = ax + return plot(*args, **kwargs) + + return _plot + + +def equal_aspect(plot): + """Decorates a plotting function returning a matplotlib axes. + Ensures the aspect ratio of the returned axes is set to equal. + Useful for 2D plots, like sim.plot() or sim_data.plot_fields() + """ + + @wraps(plot) + def _plot(*args, **kwargs) -> Ax: + """New plot function with equal aspect ratio axes returned.""" + ax = plot(*args, **kwargs) + ax.set_aspect("equal") + return ax + + return _plot + + +def set_default_labels_and_title( + axis_labels: tuple[str, str], + axis: Axis, + position: float, + ax: Ax, + plot_length_units: Optional[LengthUnit] = None, +) -> Ax: + """Adds axis labels and title to plots involving spatial dimensions. + When the ``plot_length_units`` are specified, the plot axes are scaled, and + the title and axis labels include the desired units. + """ + + import matplotlib.ticker as ticker + + xlabel = axis_labels[0] + ylabel = axis_labels[1] + if plot_length_units is not None: + if plot_length_units not in UnitScaling: + raise Tidy3dKeyError( + f"Provided units '{plot_length_units}' are not supported. " + f"Please choose one of '{LengthUnit}'." + ) + ax.set_xlabel(f"{xlabel} ({plot_length_units})") + ax.set_ylabel(f"{ylabel} ({plot_length_units})") + # Formatter to help plot in arbitrary units + scale_factor = UnitScaling[plot_length_units] + formatter = ticker.FuncFormatter(lambda y, _: f"{y * scale_factor:.2f}") + ax.xaxis.set_major_formatter(formatter) + ax.yaxis.set_major_formatter(formatter) + ax.set_title( + f"cross section at {'xyz'[axis]}={position * scale_factor:.2f} ({plot_length_units})" + ) + else: + ax.set_xlabel(xlabel) + ax.set_ylabel(ylabel) + ax.set_title(f"cross section at {'xyz'[axis]}={position:.2f}") + return ax diff --git a/tidy3d/components/viz/descartes.py b/tidy3d/components/viz/descartes.py new file mode 100644 index 0000000000..f8bd32668a --- /dev/null +++ b/tidy3d/components/viz/descartes.py @@ -0,0 +1,107 @@ +"""================================================================================================= +Descartes modified from https://pypi.org/project/descartes/ for Shapely >= 1.8.0 + +Copyright Flexcompute 2022 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from __future__ import annotations + +try: + from matplotlib.patches import PathPatch + from matplotlib.path import Path +except ImportError: + pass +from numpy import array, concatenate, ones + + +class Polygon: + """Adapt Shapely polygons to a common interface""" + + def __init__(self, context): + if isinstance(context, dict): + self.context = context["coordinates"] + else: + self.context = context + + @property + def exterior(self): + """Get polygon exterior.""" + value = getattr(self.context, "exterior", None) + if value is None: + value = self.context[0] + return value + + @property + def interiors(self): + """Get polygon interiors.""" + value = getattr(self.context, "interiors", None) + if value is None: + value = self.context[1:] + return value + + +def polygon_path(polygon): + """Constructs a compound matplotlib path from a Shapely or GeoJSON-like + geometric object""" + + def coding(obj): + # The codes will be all "LINETO" commands, except for "MOVETO"s at the + # beginning of each subpath + crds = getattr(obj, "coords", None) + if crds is None: + crds = obj + n = len(crds) + vals = ones(n, dtype=Path.code_type) * Path.LINETO + if len(vals) > 0: + vals[0] = Path.MOVETO + return vals + + ptype = polygon.geom_type + if ptype == "Polygon": + polygon = [Polygon(polygon)] + elif ptype == "MultiPolygon": + polygon = [Polygon(p) for p in polygon.geoms] + + vertices = concatenate( + [ + concatenate( + [array(t.exterior.coords)[:, :2]] + [array(r.coords)[:, :2] for r in t.interiors] + ) + for t in polygon + ] + ) + codes = concatenate( + [concatenate([coding(t.exterior)] + [coding(r) for r in t.interiors]) for t in polygon] + ) + + return Path(vertices, codes) + + +def polygon_patch(polygon, **kwargs): + """Constructs a matplotlib patch from a geometric object + + The ``polygon`` may be a Shapely or GeoJSON-like object with or without holes. + The ``kwargs`` are those supported by the matplotlib.patches.Polygon class + constructor. Returns an instance of matplotlib.patches.PathPatch. + + Example + ------- + >>> b = Point(0, 0).buffer(1.0) # doctest: +SKIP + >>> patch = PolygonPatch(b, fc='blue', ec='blue', alpha=0.5) # doctest: +SKIP + >>> axis.add_patch(patch) # doctest: +SKIP + + """ + return PathPatch(polygon_path(polygon), **kwargs) + + +"""End descartes modification +=================================================================================================""" diff --git a/tidy3d/components/viz/flex_color_palettes.py b/tidy3d/components/viz/flex_color_palettes.py new file mode 100644 index 0000000000..7fc1454a0b --- /dev/null +++ b/tidy3d/components/viz/flex_color_palettes.py @@ -0,0 +1,3306 @@ +from __future__ import annotations + +SEQUENTIAL_PALETTES_HEX = { + "flex_turquoise_seq": [ + "#ffffff", + "#fefefe", + "#fdfdfd", + "#fcfcfc", + "#fbfbfb", + "#fafbfa", + "#f9fafa", + "#f8f9f9", + "#f7f8f8", + "#f6f7f7", + "#f5f6f6", + "#f3f5f5", + "#f2f4f4", + "#f1f3f3", + "#f0f3f2", + "#eff2f1", + "#eef1f1", + "#edf0f0", + "#ecefef", + "#ebeeee", + "#eaeded", + "#e9edec", + "#e8eceb", + "#e7ebeb", + "#e6eaea", + "#e5e9e9", + "#e4e8e8", + "#e3e7e7", + "#e2e7e6", + "#e1e6e5", + "#e0e5e5", + "#dfe4e4", + "#dee3e3", + "#dde2e2", + "#dce2e1", + "#dbe1e0", + "#dae0df", + "#d9dfdf", + "#d8dede", + "#d7dedd", + "#d6dddc", + "#d5dcdb", + "#d4dbdb", + "#d3dada", + "#d2dad9", + "#d1d9d8", + "#d1d8d7", + "#d0d7d6", + "#cfd6d6", + "#ced6d5", + "#cdd5d4", + "#ccd4d3", + "#cbd3d2", + "#cad2d2", + "#c9d2d1", + "#c8d1d0", + "#c7d0cf", + "#c6cfce", + "#c5cece", + "#c4cecd", + "#c3cdcc", + "#c2cccb", + "#c1cbca", + "#c0cbca", + "#bfcac9", + "#bec9c8", + "#bec8c7", + "#bdc8c7", + "#bcc7c6", + "#bbc6c5", + "#bac5c4", + "#b9c5c3", + "#b8c4c3", + "#b7c3c2", + "#b6c2c1", + "#b5c2c0", + "#b4c1c0", + "#b3c0bf", + "#b2bfbe", + "#b2bfbd", + "#b1bebd", + "#b0bdbc", + "#afbcbb", + "#aebcba", + "#adbbba", + "#acbab9", + "#abbab8", + "#aab9b7", + "#a9b8b7", + "#a9b7b6", + "#a8b7b5", + "#a7b6b4", + "#a6b5b4", + "#a5b4b3", + "#a4b4b2", + "#a3b3b2", + "#a2b2b1", + "#a1b2b0", + "#a1b1af", + "#a0b0af", + "#9fb0ae", + "#9eafad", + "#9daeac", + "#9cadac", + "#9badab", + "#9aacaa", + "#99abaa", + "#99aba9", + "#98aaa8", + "#97a9a7", + "#96a9a7", + "#95a8a6", + "#94a7a5", + "#93a6a5", + "#92a6a4", + "#92a5a3", + "#91a4a2", + "#90a4a2", + "#8fa3a1", + "#8ea2a0", + "#8da2a0", + "#8ca19f", + "#8ca09e", + "#8ba09e", + "#8a9f9d", + "#899e9c", + "#889e9c", + "#879d9b", + "#869c9a", + "#869c9a", + "#859b99", + "#849a98", + "#839a97", + "#829997", + "#819896", + "#809895", + "#809795", + "#7f9694", + "#7e9693", + "#7d9593", + "#7c9492", + "#7b9491", + "#7a9391", + "#7a9290", + "#79928f", + "#78918f", + "#77908e", + "#76908d", + "#758f8d", + "#758f8c", + "#748e8b", + "#738d8b", + "#728d8a", + "#718c89", + "#708b89", + "#708b88", + "#6f8a87", + "#6e8987", + "#6d8986", + "#6c8885", + "#6b8885", + "#6a8784", + "#6a8684", + "#698683", + "#688582", + "#678482", + "#668481", + "#658380", + "#658280", + "#64827f", + "#63817e", + "#62817e", + "#61807d", + "#607f7c", + "#607f7c", + "#5f7e7b", + "#5e7d7b", + "#5d7d7a", + "#5c7c79", + "#5b7c79", + "#5b7b78", + "#5a7a77", + "#597a77", + "#587976", + "#577975", + "#567875", + "#567774", + "#557774", + "#547673", + "#537572", + "#527572", + "#517471", + "#507470", + "#507370", + "#4f726f", + "#4e726f", + "#4d716e", + "#4c716d", + "#4b706d", + "#4b6f6c", + "#4a6f6b", + "#496e6b", + "#486e6a", + "#476d6a", + "#466c69", + "#456c68", + "#446b68", + "#446b67", + "#436a67", + "#426966", + "#416965", + "#406865", + "#3f6864", + "#3e6763", + "#3e6663", + "#3d6662", + "#3c6562", + "#3b6561", + "#3a6460", + "#396360", + "#38635f", + "#37625f", + "#36625e", + "#35615d", + "#35605d", + "#34605c", + "#335f5c", + "#325f5b", + "#315e5a", + "#305d5a", + "#2f5d59", + "#2e5c58", + "#2d5c58", + "#2c5b57", + "#2b5a57", + "#2a5a56", + "#295955", + "#285955", + "#275854", + "#265754", + "#255753", + "#245652", + "#235652", + "#225551", + "#215551", + "#205450", + "#1e534f", + "#1d534f", + "#1c524e", + "#1b524e", + "#1a514d", + "#18504c", + "#17504c", + "#164f4b", + "#144f4b", + "#134e4a", + ], + "flex_green_seq": [ + "#ffffff", + "#fefefe", + "#fdfdfd", + "#fcfcfc", + "#fbfbfb", + "#f9fafa", + "#f8f9f9", + "#f7f8f8", + "#f6f7f7", + "#f5f6f6", + "#f4f5f5", + "#f3f5f3", + "#f2f4f2", + "#f1f3f1", + "#f0f2f0", + "#eff1ef", + "#eef0ee", + "#ecefed", + "#ebeeec", + "#eaedeb", + "#e9ecea", + "#e8ebe9", + "#e7eae8", + "#e6eae7", + "#e5e9e6", + "#e4e8e5", + "#e3e7e4", + "#e2e6e3", + "#e1e5e2", + "#e0e4e1", + "#dfe3e0", + "#dee3df", + "#dde2de", + "#dce1dd", + "#dbe0dc", + "#dadfdb", + "#d8deda", + "#d7ddd9", + "#d6dcd8", + "#d5dcd7", + "#d4dbd6", + "#d3dad5", + "#d2d9d4", + "#d1d8d3", + "#d0d7d2", + "#cfd6d1", + "#ced6d0", + "#cdd5cf", + "#ccd4ce", + "#cbd3ce", + "#cad2cd", + "#c9d1cc", + "#c8d1cb", + "#c7d0ca", + "#c6cfc9", + "#c5cec8", + "#c4cdc7", + "#c3cdc6", + "#c2ccc5", + "#c1cbc4", + "#c0cac3", + "#bfc9c2", + "#bec9c1", + "#bdc8c0", + "#bcc7bf", + "#bbc6be", + "#bac5bd", + "#b9c5bd", + "#b9c4bc", + "#b8c3bb", + "#b7c2ba", + "#b6c1b9", + "#b5c1b8", + "#b4c0b7", + "#b3bfb6", + "#b2beb5", + "#b1bdb4", + "#b0bdb3", + "#afbcb2", + "#aebbb1", + "#adbab1", + "#acbab0", + "#abb9af", + "#aab8ae", + "#a9b7ad", + "#a8b7ac", + "#a7b6ab", + "#a6b5aa", + "#a5b4a9", + "#a5b4a8", + "#a4b3a8", + "#a3b2a7", + "#a2b1a6", + "#a1b1a5", + "#a0b0a4", + "#9fafa3", + "#9eaea2", + "#9daea1", + "#9cada0", + "#9baca0", + "#9aab9f", + "#99ab9e", + "#99aa9d", + "#98a99c", + "#97a89b", + "#96a89a", + "#95a799", + "#94a699", + "#93a598", + "#92a597", + "#91a496", + "#90a395", + "#90a394", + "#8fa293", + "#8ea193", + "#8da092", + "#8ca091", + "#8b9f90", + "#8a9e8f", + "#899e8e", + "#889d8d", + "#879c8d", + "#879b8c", + "#869b8b", + "#859a8a", + "#849989", + "#839988", + "#829888", + "#819787", + "#809786", + "#809685", + "#7f9584", + "#7e9483", + "#7d9483", + "#7c9382", + "#7b9281", + "#7a9280", + "#79917f", + "#79907e", + "#78907e", + "#778f7d", + "#768e7c", + "#758e7b", + "#748d7a", + "#738c79", + "#728c79", + "#728b78", + "#718a77", + "#708a76", + "#6f8975", + "#6e8875", + "#6d8774", + "#6c8773", + "#6c8672", + "#6b8571", + "#6a8571", + "#698470", + "#68836f", + "#67836e", + "#66826d", + "#66816d", + "#65816c", + "#64806b", + "#637f6a", + "#627f69", + "#617e69", + "#607d68", + "#607d67", + "#5f7c66", + "#5e7c65", + "#5d7b65", + "#5c7a64", + "#5b7a63", + "#5a7962", + "#5a7861", + "#597861", + "#587760", + "#57765f", + "#56765e", + "#55755d", + "#55745d", + "#54745c", + "#53735b", + "#52725a", + "#51725a", + "#507159", + "#4f7058", + "#4f7057", + "#4e6f56", + "#4d6e56", + "#4c6e55", + "#4b6d54", + "#4a6d53", + "#4a6c53", + "#496b52", + "#486b51", + "#476a50", + "#466950", + "#45694f", + "#44684e", + "#44674d", + "#43674c", + "#42664c", + "#41654b", + "#40654a", + "#3f6449", + "#3e6449", + "#3e6348", + "#3d6247", + "#3c6246", + "#3b6146", + "#3a6045", + "#396044", + "#385f43", + "#385e43", + "#375e42", + "#365d41", + "#355c40", + "#345c40", + "#335b3f", + "#325b3e", + "#315a3d", + "#30593d", + "#30593c", + "#2f583b", + "#2e573a", + "#2d573a", + "#2c5639", + "#2b5538", + "#2a5537", + "#295437", + "#285436", + "#275335", + "#265234", + "#265234", + "#255133", + "#245032", + "#235031", + "#224f31", + "#214e30", + "#204e2f", + "#1f4d2e", + "#1e4c2e", + "#1d4c2d", + "#1c4b2c", + "#1b4b2b", + "#1a4a2b", + "#18492a", + "#174929", + "#164828", + "#154728", + "#144727", + "#134626", + "#124525", + "#104525", + "#0f4424", + ], + "flex_blue_seq": [ + "#ffffff", + "#fefefe", + "#fdfdfd", + "#fbfcfc", + "#fafbfb", + "#f9fafa", + "#f8f9f9", + "#f7f7f8", + "#f6f6f8", + "#f4f5f7", + "#f3f4f6", + "#f2f3f5", + "#f1f2f4", + "#f0f1f3", + "#eff0f2", + "#eeeff1", + "#eceef0", + "#ebedf0", + "#eaecef", + "#e9ebee", + "#e8eaed", + "#e7e9ec", + "#e6e8eb", + "#e4e7ea", + "#e3e6ea", + "#e2e5e9", + "#e1e4e8", + "#e0e3e7", + "#dfe2e6", + "#dee1e5", + "#dde0e5", + "#dcdfe4", + "#dadee3", + "#d9dde2", + "#d8dce1", + "#d7dbe0", + "#d6dae0", + "#d5d9df", + "#d4d8de", + "#d3d7dd", + "#d2d6dc", + "#d1d5dc", + "#d0d4db", + "#cfd3da", + "#ced2d9", + "#ccd1d9", + "#cbd0d8", + "#cacfd7", + "#c9ced6", + "#c8cdd5", + "#c7ccd5", + "#c6ccd4", + "#c5cbd3", + "#c4cad2", + "#c3c9d2", + "#c2c8d1", + "#c1c7d0", + "#c0c6cf", + "#bfc5cf", + "#bec4ce", + "#bdc3cd", + "#bcc2cd", + "#bbc1cc", + "#bac0cb", + "#b9c0ca", + "#b8bfca", + "#b7bec9", + "#b6bdc8", + "#b5bcc7", + "#b4bbc7", + "#b3bac6", + "#b2b9c5", + "#b1b8c5", + "#b0b7c4", + "#afb7c3", + "#aeb6c3", + "#adb5c2", + "#acb4c1", + "#abb3c1", + "#aab2c0", + "#a9b1bf", + "#a8b0be", + "#a7b0be", + "#a6afbd", + "#a5aebc", + "#a4adbc", + "#a3acbb", + "#a2abba", + "#a1aaba", + "#a0aab9", + "#9fa9b8", + "#9ea8b8", + "#9da7b7", + "#9ca6b7", + "#9ba5b6", + "#9aa4b5", + "#99a4b5", + "#98a3b4", + "#97a2b3", + "#96a1b3", + "#95a0b2", + "#949fb1", + "#939fb1", + "#929eb0", + "#919db0", + "#909caf", + "#8f9bae", + "#8f9aae", + "#8e9aad", + "#8d99ac", + "#8c98ac", + "#8b97ab", + "#8a96ab", + "#8996aa", + "#8895a9", + "#8794a9", + "#8693a8", + "#8592a8", + "#8492a7", + "#8391a6", + "#8290a6", + "#818fa5", + "#818ea5", + "#808ea4", + "#7f8da3", + "#7e8ca3", + "#7d8ba2", + "#7c8aa2", + "#7b8aa1", + "#7a89a1", + "#7988a0", + "#78879f", + "#77869f", + "#76869e", + "#76859e", + "#75849d", + "#74839d", + "#73829c", + "#72829b", + "#71819b", + "#70809a", + "#6f7f9a", + "#6e7f99", + "#6d7e99", + "#6c7d98", + "#6c7c98", + "#6b7c97", + "#6a7b97", + "#697a96", + "#687995", + "#677895", + "#667894", + "#657794", + "#647693", + "#637593", + "#637592", + "#627492", + "#617391", + "#607291", + "#5f7290", + "#5e7190", + "#5d708f", + "#5c6f8f", + "#5b6f8e", + "#5b6e8e", + "#5a6d8d", + "#596c8c", + "#586b8c", + "#576b8b", + "#566a8b", + "#55698a", + "#54688a", + "#536889", + "#536789", + "#526688", + "#516588", + "#506587", + "#4f6487", + "#4e6386", + "#4d6286", + "#4c6285", + "#4b6185", + "#4a6084", + "#4a5f84", + "#495f83", + "#485e83", + "#475d83", + "#465d82", + "#455c82", + "#445b81", + "#435a81", + "#425a80", + "#425980", + "#41587f", + "#40577f", + "#3f577e", + "#3e567e", + "#3d557d", + "#3c547d", + "#3b547c", + "#3a537c", + "#39527b", + "#39517b", + "#38517b", + "#37507a", + "#364f7a", + "#354e79", + "#344e79", + "#334d78", + "#324c78", + "#314b77", + "#304b77", + "#2f4a76", + "#2e4976", + "#2d4876", + "#2c4875", + "#2c4775", + "#2b4674", + "#2a4574", + "#294473", + "#284473", + "#274373", + "#264272", + "#254172", + "#244171", + "#234071", + "#223f70", + "#213e70", + "#203e70", + "#1f3d6f", + "#1e3c6f", + "#1d3b6e", + "#1c3a6e", + "#1b3a6e", + "#1a396d", + "#19386d", + "#17376c", + "#16366c", + "#15366c", + "#14356b", + "#13346b", + "#12336b", + "#10326a", + "#0f326a", + "#0e316a", + "#0d3069", + "#0b2f69", + "#0a2e68", + "#082d68", + "#072c68", + "#062c68", + "#042b67", + "#032a67", + "#022967", + "#012866", + "#002766", + ], + "flex_orange_seq": [ + "#ffffff", + "#fefefe", + "#fefdfd", + "#fdfdfc", + "#fdfcfb", + "#fcfbfa", + "#fbfafa", + "#fbf9f9", + "#faf9f8", + "#faf8f7", + "#f9f7f6", + "#f8f6f5", + "#f8f6f4", + "#f7f5f3", + "#f7f4f2", + "#f6f3f1", + "#f5f2f1", + "#f5f2f0", + "#f4f1ef", + "#f3f0ee", + "#f3efed", + "#f2efec", + "#f2eeeb", + "#f1edea", + "#f1ece9", + "#f0ece8", + "#f0ebe7", + "#efeae6", + "#efe9e5", + "#eee9e4", + "#eee8e3", + "#ede7e2", + "#ede6e1", + "#ece5e0", + "#ece5df", + "#ebe4de", + "#ebe3dd", + "#eae2dc", + "#eae2db", + "#e9e1da", + "#e9e0d9", + "#e9dfd8", + "#e8dfd7", + "#e8ded6", + "#e7ddd5", + "#e7dcd4", + "#e6dbd3", + "#e6dbd2", + "#e6dad1", + "#e5d9d0", + "#e5d8cf", + "#e4d8ce", + "#e4d7cd", + "#e3d6cc", + "#e3d5cb", + "#e3d5ca", + "#e2d4c9", + "#e2d3c8", + "#e1d2c7", + "#e1d2c6", + "#e0d1c5", + "#e0d0c4", + "#e0cfc3", + "#dfcfc2", + "#dfcec1", + "#decdc0", + "#deccbf", + "#deccbe", + "#ddcbbd", + "#ddcabc", + "#dcc9bb", + "#dcc9ba", + "#dcc8b9", + "#dbc7b8", + "#dbc6b8", + "#dbc6b7", + "#dac5b6", + "#dac4b5", + "#d9c4b4", + "#d9c3b3", + "#d9c2b2", + "#d8c1b1", + "#d8c1b0", + "#d7c0af", + "#d7bfae", + "#d7bead", + "#d6beac", + "#d6bdab", + "#d6bcaa", + "#d5bba9", + "#d5bba8", + "#d4baa7", + "#d4b9a6", + "#d4b9a5", + "#d3b8a4", + "#d3b7a3", + "#d3b6a2", + "#d2b6a1", + "#d2b5a0", + "#d2b49f", + "#d1b49e", + "#d1b39d", + "#d0b29c", + "#d0b19b", + "#d0b19a", + "#cfb099", + "#cfaf99", + "#cfaf98", + "#ceae97", + "#cead96", + "#ceac95", + "#cdac94", + "#cdab93", + "#cdaa92", + "#ccaa91", + "#cca990", + "#cca88f", + "#cba78e", + "#cba78d", + "#caa68c", + "#caa58b", + "#caa58a", + "#c9a489", + "#c9a388", + "#c9a387", + "#c8a286", + "#c8a185", + "#c8a085", + "#c7a084", + "#c79f83", + "#c79e82", + "#c69e81", + "#c69d80", + "#c69c7f", + "#c59c7e", + "#c59b7d", + "#c59a7c", + "#c4997b", + "#c4997a", + "#c49879", + "#c39778", + "#c39777", + "#c29676", + "#c29575", + "#c29575", + "#c19474", + "#c19373", + "#c19372", + "#c09271", + "#c09170", + "#c0906f", + "#bf906e", + "#bf8f6d", + "#bf8e6c", + "#be8e6b", + "#be8d6a", + "#be8c69", + "#bd8c68", + "#bd8b67", + "#bd8a67", + "#bc8a66", + "#bc8965", + "#bc8864", + "#bb8863", + "#bb8762", + "#bb8661", + "#ba8660", + "#ba855f", + "#ba845e", + "#b9835d", + "#b9835c", + "#b8825b", + "#b8815b", + "#b8815a", + "#b78059", + "#b77f58", + "#b77f57", + "#b67e56", + "#b67d55", + "#b67d54", + "#b57c53", + "#b57b52", + "#b57b51", + "#b47a50", + "#b4794f", + "#b4794f", + "#b3784e", + "#b3774d", + "#b3774c", + "#b2764b", + "#b2754a", + "#b17549", + "#b17448", + "#b17347", + "#b07346", + "#b07245", + "#b07144", + "#af7144", + "#af7043", + "#af6f42", + "#ae6f41", + "#ae6e40", + "#ae6d3f", + "#ad6d3e", + "#ad6c3d", + "#ac6b3c", + "#ac6b3b", + "#ac6a3a", + "#ab6939", + "#ab6939", + "#ab6838", + "#aa6737", + "#aa6736", + "#aa6635", + "#a96534", + "#a96533", + "#a86432", + "#a86331", + "#a86330", + "#a7622f", + "#a7612e", + "#a7612d", + "#a6602c", + "#a65f2b", + "#a55f2a", + "#a55e2a", + "#a55d29", + "#a45d28", + "#a45c27", + "#a35b26", + "#a35b25", + "#a35a24", + "#a25923", + "#a25922", + "#a25821", + "#a15720", + "#a1571f", + "#a0561e", + "#a0551d", + "#a0551c", + "#9f541b", + "#9f531a", + "#9e5318", + "#9e5217", + "#9e5116", + "#9d5115", + "#9d5014", + "#9c4f13", + "#9c4f12", + "#9b4e10", + "#9b4d0f", + "#9b4d0e", + "#9a4c0c", + "#9a4b0b", + "#994b09", + "#994a08", + ], + "flex_red_seq": [ + "#ffffff", + "#fefefe", + "#fefdfd", + "#fdfcfc", + "#fcfbfb", + "#fcfafa", + "#fbf9f9", + "#faf8f8", + "#faf7f7", + "#f9f6f6", + "#f8f5f5", + "#f8f4f5", + "#f7f3f4", + "#f6f2f3", + "#f5f2f2", + "#f5f1f1", + "#f4f0f0", + "#f3efef", + "#f3eeee", + "#f2eded", + "#f1ecec", + "#f1ebec", + "#f0eaeb", + "#efe9ea", + "#efe8e9", + "#eee7e8", + "#eee6e7", + "#ede5e6", + "#ece4e6", + "#ece3e5", + "#ebe2e4", + "#ebe1e3", + "#eae0e2", + "#eae0e1", + "#e9dfe0", + "#e9dedf", + "#e8dddf", + "#e8dcde", + "#e7dbdd", + "#e7dadc", + "#e6d9db", + "#e6d8da", + "#e5d7d9", + "#e5d6d8", + "#e4d5d7", + "#e4d4d7", + "#e3d3d6", + "#e3d2d5", + "#e2d1d4", + "#e2d0d3", + "#e1d0d2", + "#e1cfd1", + "#e0ced1", + "#e0cdd0", + "#dfcccf", + "#dfcbce", + "#decacd", + "#dec9cc", + "#ddc8cb", + "#ddc7cb", + "#dcc6ca", + "#dcc5c9", + "#dbc4c8", + "#dbc4c7", + "#dbc3c6", + "#dac2c5", + "#dac1c5", + "#d9c0c4", + "#d9bfc3", + "#d8bec2", + "#d8bdc1", + "#d7bcc0", + "#d7bbc0", + "#d7babf", + "#d6babe", + "#d6b9bd", + "#d5b8bc", + "#d5b7bb", + "#d4b6bb", + "#d4b5ba", + "#d4b4b9", + "#d3b3b8", + "#d3b2b7", + "#d2b1b6", + "#d2b0b6", + "#d1b0b5", + "#d1afb4", + "#d1aeb3", + "#d0adb2", + "#d0acb1", + "#cfabb1", + "#cfaab0", + "#cfa9af", + "#cea8ae", + "#cea8ad", + "#cda7ad", + "#cda6ac", + "#cca5ab", + "#cca4aa", + "#cca3a9", + "#cba2a9", + "#cba1a8", + "#caa0a7", + "#caa0a6", + "#ca9fa5", + "#c99ea5", + "#c99da4", + "#c89ca3", + "#c89ba2", + "#c89aa1", + "#c799a1", + "#c799a0", + "#c6989f", + "#c6979e", + "#c6969d", + "#c5959d", + "#c5949c", + "#c4939b", + "#c4929a", + "#c49299", + "#c39199", + "#c39098", + "#c28f97", + "#c28e96", + "#c28d96", + "#c18c95", + "#c18c94", + "#c18b93", + "#c08a92", + "#c08992", + "#bf8891", + "#bf8790", + "#bf868f", + "#be858f", + "#be858e", + "#bd848d", + "#bd838c", + "#bd828c", + "#bc818b", + "#bc808a", + "#bb7f89", + "#bb7f88", + "#bb7e88", + "#ba7d87", + "#ba7c86", + "#b97b85", + "#b97a85", + "#b97984", + "#b87983", + "#b87882", + "#b87782", + "#b77681", + "#b77580", + "#b6747f", + "#b6737f", + "#b6737e", + "#b5727d", + "#b5717c", + "#b4707c", + "#b46f7b", + "#b46e7a", + "#b36d79", + "#b36d79", + "#b26c78", + "#b26b77", + "#b26a76", + "#b16976", + "#b16875", + "#b06774", + "#b06773", + "#b06673", + "#af6572", + "#af6471", + "#ae6371", + "#ae6270", + "#ae616f", + "#ad616e", + "#ad606e", + "#ac5f6d", + "#ac5e6c", + "#ab5d6b", + "#ab5c6b", + "#ab5b6a", + "#aa5b69", + "#aa5a69", + "#a95968", + "#a95867", + "#a95766", + "#a85666", + "#a85565", + "#a75464", + "#a75463", + "#a65363", + "#a65262", + "#a65161", + "#a55061", + "#a54f60", + "#a44e5f", + "#a44d5e", + "#a34d5e", + "#a34c5d", + "#a34b5c", + "#a24a5c", + "#a2495b", + "#a1485a", + "#a1475a", + "#a04659", + "#a04558", + "#9f4557", + "#9f4457", + "#9f4356", + "#9e4255", + "#9e4155", + "#9d4054", + "#9d3f53", + "#9c3e52", + "#9c3d52", + "#9b3c51", + "#9b3b50", + "#9a3b50", + "#9a3a4f", + "#99394e", + "#99384e", + "#98374d", + "#98364c", + "#98354b", + "#97344b", + "#97334a", + "#963249", + "#963149", + "#953048", + "#952f47", + "#942e47", + "#942d46", + "#932c45", + "#932b45", + "#922a44", + "#922943", + "#912843", + "#912742", + "#902641", + "#902540", + "#8f2440", + "#8e223f", + "#8e213e", + "#8d203e", + "#8d1f3d", + "#8c1e3c", + "#8c1d3c", + "#8b1b3b", + "#8b1a3a", + "#8a193a", + "#8a1739", + "#891638", + "#891438", + "#881337", + ], + "flex_purple_seq": [ + "#ffffff", + "#fefefe", + "#fdfdfd", + "#fcfcfd", + "#fbfbfc", + "#fafafb", + "#f9f9fa", + "#f8f8f9", + "#f7f7f9", + "#f6f6f8", + "#f5f5f7", + "#f4f4f6", + "#f3f3f6", + "#f2f2f5", + "#f1f1f4", + "#f0f0f3", + "#efeff3", + "#eeeef2", + "#ededf1", + "#ececf0", + "#ebebf0", + "#eaeaef", + "#e9e9ee", + "#e8e8ed", + "#e8e8ed", + "#e7e7ec", + "#e6e6eb", + "#e5e5eb", + "#e4e4ea", + "#e3e3e9", + "#e2e2e8", + "#e1e1e8", + "#e0e0e7", + "#dfdfe6", + "#dedee6", + "#dddde5", + "#dcdce4", + "#dbdbe4", + "#dadae3", + "#d9dae2", + "#d9d9e2", + "#d8d8e1", + "#d7d7e0", + "#d6d6e0", + "#d5d5df", + "#d4d4df", + "#d3d3de", + "#d2d2dd", + "#d1d1dd", + "#d0d1dc", + "#d0d0db", + "#cfcfdb", + "#ceceda", + "#cdcdd9", + "#ccccd9", + "#cbcbd8", + "#cacad8", + "#c9c9d7", + "#c8c9d6", + "#c8c8d6", + "#c7c7d5", + "#c6c6d5", + "#c5c5d4", + "#c4c4d3", + "#c3c3d3", + "#c2c2d2", + "#c2c2d2", + "#c1c1d1", + "#c0c0d1", + "#bfbfd0", + "#bebecf", + "#bdbdcf", + "#bcbcce", + "#bcbcce", + "#bbbbcd", + "#babacd", + "#b9b9cc", + "#b8b8cc", + "#b7b7cb", + "#b7b7ca", + "#b6b6ca", + "#b5b5c9", + "#b4b4c9", + "#b3b3c8", + "#b3b2c8", + "#b2b2c7", + "#b1b1c7", + "#b0b0c6", + "#afafc6", + "#aeaec5", + "#aeadc5", + "#adadc4", + "#acacc4", + "#ababc3", + "#aaaac3", + "#aaa9c2", + "#a9a8c2", + "#a8a8c1", + "#a7a7c1", + "#a6a6c0", + "#a6a5c0", + "#a5a4bf", + "#a4a4bf", + "#a3a3be", + "#a3a2be", + "#a2a1bd", + "#a1a0bd", + "#a0a0bc", + "#9f9fbc", + "#9f9ebb", + "#9e9dbb", + "#9d9cba", + "#9c9cba", + "#9c9bb9", + "#9b9ab9", + "#9a99b8", + "#9998b8", + "#9998b8", + "#9897b7", + "#9796b7", + "#9695b6", + "#9694b6", + "#9594b5", + "#9493b5", + "#9392b4", + "#9391b4", + "#9291b4", + "#9190b3", + "#908fb3", + "#908eb2", + "#8f8db2", + "#8e8db1", + "#8d8cb1", + "#8d8bb1", + "#8c8ab0", + "#8b8ab0", + "#8a89af", + "#8a88af", + "#8987ae", + "#8886ae", + "#8886ae", + "#8785ad", + "#8684ad", + "#8583ac", + "#8583ac", + "#8482ac", + "#8381ab", + "#8280ab", + "#8280ab", + "#817faa", + "#807eaa", + "#807da9", + "#7f7ca9", + "#7e7ca9", + "#7e7ba8", + "#7d7aa8", + "#7c79a8", + "#7b79a7", + "#7b78a7", + "#7a77a6", + "#7976a6", + "#7976a6", + "#7875a5", + "#7774a5", + "#7773a5", + "#7673a4", + "#7572a4", + "#7571a4", + "#7470a3", + "#736fa3", + "#736fa3", + "#726ea2", + "#716da2", + "#716ca2", + "#706ca1", + "#6f6ba1", + "#6f6aa1", + "#6e69a0", + "#6d69a0", + "#6d68a0", + "#6c679f", + "#6b669f", + "#6b669f", + "#6a659e", + "#69649e", + "#69639e", + "#68629d", + "#67629d", + "#67619d", + "#66609d", + "#655f9c", + "#655f9c", + "#645e9c", + "#635d9b", + "#635c9b", + "#625c9b", + "#625b9b", + "#615a9a", + "#60599a", + "#60589a", + "#5f589a", + "#5e5799", + "#5e5699", + "#5d5599", + "#5d5498", + "#5c5498", + "#5b5398", + "#5b5298", + "#5a5198", + "#595097", + "#595097", + "#584f97", + "#584e97", + "#574d96", + "#564c96", + "#564c96", + "#554b96", + "#554a95", + "#544995", + "#544895", + "#534795", + "#524795", + "#524694", + "#514594", + "#514494", + "#504394", + "#504294", + "#4f4294", + "#4e4193", + "#4e4093", + "#4d3f93", + "#4d3e93", + "#4c3d93", + "#4c3c93", + "#4b3b93", + "#4b3a92", + "#4a3992", + "#4a3892", + "#493892", + "#493792", + "#483692", + "#483592", + "#473492", + "#473391", + "#463291", + "#463191", + "#452f91", + "#452e91", + "#442d91", + "#442c91", + "#432b91", + "#432a91", + "#422991", + "#422891", + "#412691", + "#412591", + ], + "flex_grey_seq": [ + "#ffffff", + "#fefefe", + "#fdfdfd", + "#fcfcfc", + "#fbfbfc", + "#fafafb", + "#f9f9fa", + "#f8f9f9", + "#f8f8f8", + "#f7f7f7", + "#f6f6f6", + "#f5f5f6", + "#f4f4f5", + "#f3f3f4", + "#f2f2f3", + "#f1f1f2", + "#f0f0f1", + "#eff0f1", + "#eeeff0", + "#eeeeef", + "#ededee", + "#ececed", + "#ebebec", + "#eaeaec", + "#e9e9eb", + "#e8e9ea", + "#e7e8e9", + "#e6e7e8", + "#e6e6e8", + "#e5e5e7", + "#e4e4e6", + "#e3e3e5", + "#e2e3e4", + "#e1e2e4", + "#e0e1e3", + "#dfe0e2", + "#dfdfe1", + "#dedee0", + "#dddde0", + "#dcdddf", + "#dbdcde", + "#dadbdd", + "#d9dadd", + "#d9d9dc", + "#d8d8db", + "#d7d8da", + "#d6d7da", + "#d5d6d9", + "#d4d5d8", + "#d4d4d7", + "#d3d4d6", + "#d2d3d6", + "#d1d2d5", + "#d0d1d4", + "#cfd0d3", + "#cfcfd3", + "#cecfd2", + "#cdced1", + "#cccdd0", + "#cbccd0", + "#cacbcf", + "#cacbce", + "#c9cace", + "#c8c9cd", + "#c7c8cc", + "#c6c8cb", + "#c6c7cb", + "#c5c6ca", + "#c4c5c9", + "#c3c4c8", + "#c2c4c8", + "#c2c3c7", + "#c1c2c6", + "#c0c1c6", + "#bfc0c5", + "#bec0c4", + "#bebfc3", + "#bdbec3", + "#bcbdc2", + "#bbbdc1", + "#babcc1", + "#babbc0", + "#b9babf", + "#b8babe", + "#b7b9be", + "#b7b8bd", + "#b6b7bc", + "#b5b7bc", + "#b4b6bb", + "#b3b5ba", + "#b3b4ba", + "#b2b4b9", + "#b1b3b8", + "#b0b2b8", + "#b0b1b7", + "#afb1b6", + "#aeb0b6", + "#adafb5", + "#adaeb4", + "#acaeb3", + "#abadb3", + "#aaacb2", + "#aaabb1", + "#a9abb1", + "#a8aab0", + "#a7a9af", + "#a7a8af", + "#a6a8ae", + "#a5a7ad", + "#a4a6ad", + "#a4a6ac", + "#a3a5ab", + "#a2a4ab", + "#a1a3aa", + "#a1a3aa", + "#a0a2a9", + "#9fa1a8", + "#9ea1a8", + "#9ea0a7", + "#9d9fa6", + "#9c9ea6", + "#9c9ea5", + "#9b9da4", + "#9a9ca4", + "#999ca3", + "#999ba2", + "#989aa2", + "#979aa1", + "#9799a0", + "#9698a0", + "#95979f", + "#94979f", + "#94969e", + "#93959d", + "#92959d", + "#92949c", + "#91939b", + "#90939b", + "#8f929a", + "#8f919a", + "#8e9199", + "#8d9098", + "#8d8f98", + "#8c8e97", + "#8b8e96", + "#8b8d96", + "#8a8c95", + "#898c95", + "#888b94", + "#888a93", + "#878a93", + "#868992", + "#868891", + "#858891", + "#848790", + "#848690", + "#83868f", + "#82858e", + "#82848e", + "#81848d", + "#80838d", + "#80828c", + "#7f828b", + "#7e818b", + "#7e808a", + "#7d808a", + "#7c7f89", + "#7b7e88", + "#7b7e88", + "#7a7d87", + "#797c87", + "#797c86", + "#787b85", + "#777a85", + "#777a84", + "#767984", + "#757983", + "#757882", + "#747782", + "#737781", + "#737681", + "#727580", + "#71757f", + "#71747f", + "#70737e", + "#70737e", + "#6f727d", + "#6e717d", + "#6e717c", + "#6d707b", + "#6c707b", + "#6c6f7a", + "#6b6e7a", + "#6a6e79", + "#6a6d79", + "#696c78", + "#686c77", + "#686b77", + "#676a76", + "#666a76", + "#666975", + "#656974", + "#646874", + "#646773", + "#636773", + "#636672", + "#626572", + "#616571", + "#616470", + "#606370", + "#5f636f", + "#5f626f", + "#5e626e", + "#5d616e", + "#5d606d", + "#5c606c", + "#5b5f6c", + "#5b5e6b", + "#5a5e6b", + "#5a5d6a", + "#595d6a", + "#585c69", + "#585b69", + "#575b68", + "#565a67", + "#565967", + "#555966", + "#555866", + "#545865", + "#535765", + "#535664", + "#525663", + "#515563", + "#515562", + "#505462", + "#4f5361", + "#4f5361", + "#4e5260", + "#4e5160", + "#4d515f", + "#4c505e", + "#4c505e", + "#4b4f5d", + "#4a4e5d", + "#4a4e5c", + "#494d5c", + "#494d5b", + "#484c5a", + "#474b5a", + "#474b59", + "#464a59", + "#454958", + "#454958", + "#444857", + "#444857", + "#434756", + ], +} +CATEGORICAL_PALETTES_HEX = { + "flex_distinct": [ + "#176737", + "#FF7B0D", + "#979BAA", + "#F44E6A", + "#0062FF", + "#26AB5B", + "#6D3EF2", + "#F59E0B", + ] +} +DIVERGING_PALETTES_HEX = { + "flex_BuRd": [ + "#002766", + "#022967", + "#052b67", + "#072d68", + "#0a2e69", + "#0d3069", + "#10326a", + "#12346b", + "#15356c", + "#17376c", + "#1a396d", + "#1c3a6e", + "#1e3c6f", + "#203e70", + "#223f71", + "#244171", + "#264372", + "#284473", + "#2a4674", + "#2c4775", + "#2e4976", + "#304a77", + "#324c78", + "#344e79", + "#364f7a", + "#38517b", + "#3a527c", + "#3c547d", + "#3e557e", + "#3f577f", + "#415980", + "#435a80", + "#455c81", + "#475d83", + "#495f84", + "#4b6085", + "#4c6286", + "#4e6387", + "#506588", + "#526789", + "#54688a", + "#566a8b", + "#586b8c", + "#5a6d8d", + "#5b6e8e", + "#5d708f", + "#5f7290", + "#617391", + "#637592", + "#657694", + "#677895", + "#687a96", + "#6a7b97", + "#6c7d98", + "#6e7e99", + "#70809a", + "#72829b", + "#74839d", + "#76859e", + "#78879f", + "#7a88a0", + "#7b8aa1", + "#7d8ca3", + "#7f8da4", + "#818fa5", + "#8391a6", + "#8592a8", + "#8794a9", + "#8996aa", + "#8b97ab", + "#8d99ad", + "#8f9bae", + "#919daf", + "#939eb1", + "#95a0b2", + "#97a2b3", + "#99a4b4", + "#9ba5b6", + "#9da7b7", + "#9fa9b9", + "#a1abba", + "#a3acbb", + "#a5aebd", + "#a7b0be", + "#a9b2c0", + "#abb4c1", + "#adb6c2", + "#afb7c4", + "#b1b9c5", + "#b4bbc7", + "#b6bdc8", + "#b8bfca", + "#bac1cb", + "#bcc3cd", + "#bec5ce", + "#c0c6d0", + "#c3c8d1", + "#c5cad3", + "#c7ccd5", + "#c9ced6", + "#cbd0d8", + "#ced2d9", + "#d0d4db", + "#d2d6dd", + "#d4d8de", + "#d7dae0", + "#d9dce2", + "#dbdee3", + "#dee0e5", + "#e0e3e7", + "#e2e5e9", + "#e4e7ea", + "#e7e9ec", + "#e9ebee", + "#ecedf0", + "#eeeff2", + "#f0f2f3", + "#f3f4f5", + "#f5f6f7", + "#f8f8f9", + "#fafafb", + "#fdfdfd", + "#FFFFFF", + "#fefdfd", + "#fcfbfb", + "#fbf9f9", + "#f9f7f7", + "#f8f5f5", + "#f6f3f3", + "#f5f1f1", + "#f4efef", + "#f2edee", + "#f1ebec", + "#efe9ea", + "#eee7e8", + "#ede5e6", + "#ece3e4", + "#ebe1e3", + "#e9dfe1", + "#e8dddf", + "#e7dbdd", + "#e6d9db", + "#e5d7d9", + "#e4d5d8", + "#e3d3d6", + "#e2d1d4", + "#e1cfd2", + "#e0cdd0", + "#dfcccf", + "#decacd", + "#ddc8cb", + "#dcc6c9", + "#dbc4c7", + "#dac2c6", + "#d9c0c4", + "#d8bec2", + "#d7bcc0", + "#d6babf", + "#d6b8bd", + "#d5b6bb", + "#d4b5b9", + "#d3b3b8", + "#d2b1b6", + "#d1afb4", + "#d0adb2", + "#cfabb1", + "#cfa9af", + "#cea8ad", + "#cda6ac", + "#cca4aa", + "#cba2a8", + "#caa0a7", + "#c99ea5", + "#c99ca3", + "#c89ba2", + "#c799a0", + "#c6979e", + "#c5959d", + "#c4939b", + "#c49199", + "#c39098", + "#c28e96", + "#c18c94", + "#c08a93", + "#c08891", + "#bf8790", + "#be858e", + "#bd838c", + "#bc818b", + "#bb7f89", + "#bb7e88", + "#ba7c86", + "#b97a84", + "#b87883", + "#b77681", + "#b67580", + "#b6737e", + "#b5717d", + "#b46f7b", + "#b36d79", + "#b26c78", + "#b26a76", + "#b16875", + "#b06673", + "#af6572", + "#ae6370", + "#ad616f", + "#ac5f6d", + "#ac5d6c", + "#ab5c6a", + "#aa5a69", + "#a95867", + "#a85666", + "#a75464", + "#a65263", + "#a55161", + "#a44f60", + "#a44d5e", + "#a34b5d", + "#a2495b", + "#a1475a", + "#a04658", + "#9f4457", + "#9e4255", + "#9d4054", + "#9c3e52", + "#9b3c51", + "#9a3a4f", + "#99384e", + "#98364c", + "#97344b", + "#96324a", + "#953048", + "#942e47", + "#932c45", + "#922a44", + "#912842", + "#902541", + "#8f233f", + "#8e213e", + "#8d1e3d", + "#8b1c3b", + "#8a193a", + "#891638", + "#881337", + ], + "flex_RdBu": [ + "#881337", + "#891638", + "#8a193a", + "#8b1c3b", + "#8d1e3d", + "#8e213e", + "#8f233f", + "#902541", + "#912842", + "#922a44", + "#932c45", + "#942e47", + "#953048", + "#96324a", + "#97344b", + "#98364c", + "#99384e", + "#9a3a4f", + "#9b3c51", + "#9c3e52", + "#9d4054", + "#9e4255", + "#9f4457", + "#a04658", + "#a1475a", + "#a2495b", + "#a34b5d", + "#a44d5e", + "#a44f60", + "#a55161", + "#a65263", + "#a75464", + "#a85666", + "#a95867", + "#aa5a69", + "#ab5c6a", + "#ac5d6c", + "#ac5f6d", + "#ad616f", + "#ae6370", + "#af6572", + "#b06673", + "#b16875", + "#b26a76", + "#b26c78", + "#b36d79", + "#b46f7b", + "#b5717d", + "#b6737e", + "#b67580", + "#b77681", + "#b87883", + "#b97a84", + "#ba7c86", + "#bb7e88", + "#bb7f89", + "#bc818b", + "#bd838c", + "#be858e", + "#bf8790", + "#c08891", + "#c08a93", + "#c18c94", + "#c28e96", + "#c39098", + "#c49199", + "#c4939b", + "#c5959d", + "#c6979e", + "#c799a0", + "#c89ba2", + "#c99ca3", + "#c99ea5", + "#caa0a7", + "#cba2a8", + "#cca4aa", + "#cda6ac", + "#cea8ad", + "#cfa9af", + "#cfabb1", + "#d0adb2", + "#d1afb4", + "#d2b1b6", + "#d3b3b8", + "#d4b5b9", + "#d5b6bb", + "#d6b8bd", + "#d6babf", + "#d7bcc0", + "#d8bec2", + "#d9c0c4", + "#dac2c6", + "#dbc4c7", + "#dcc6c9", + "#ddc8cb", + "#decacd", + "#dfcccf", + "#e0cdd0", + "#e1cfd2", + "#e2d1d4", + "#e3d3d6", + "#e4d5d8", + "#e5d7d9", + "#e6d9db", + "#e7dbdd", + "#e8dddf", + "#e9dfe1", + "#ebe1e3", + "#ece3e4", + "#ede5e6", + "#eee7e8", + "#efe9ea", + "#f1ebec", + "#f2edee", + "#f4efef", + "#f5f1f1", + "#f6f3f3", + "#f8f5f5", + "#f9f7f7", + "#fbf9f9", + "#fcfbfb", + "#fefdfd", + "#FFFFFF", + "#fdfdfd", + "#fafafb", + "#f8f8f9", + "#f5f6f7", + "#f3f4f5", + "#f0f2f3", + "#eeeff2", + "#ecedf0", + "#e9ebee", + "#e7e9ec", + "#e4e7ea", + "#e2e5e9", + "#e0e3e7", + "#dee0e5", + "#dbdee3", + "#d9dce2", + "#d7dae0", + "#d4d8de", + "#d2d6dd", + "#d0d4db", + "#ced2d9", + "#cbd0d8", + "#c9ced6", + "#c7ccd5", + "#c5cad3", + "#c3c8d1", + "#c0c6d0", + "#bec5ce", + "#bcc3cd", + "#bac1cb", + "#b8bfca", + "#b6bdc8", + "#b4bbc7", + "#b1b9c5", + "#afb7c4", + "#adb6c2", + "#abb4c1", + "#a9b2c0", + "#a7b0be", + "#a5aebd", + "#a3acbb", + "#a1abba", + "#9fa9b9", + "#9da7b7", + "#9ba5b6", + "#99a4b4", + "#97a2b3", + "#95a0b2", + "#939eb1", + "#919daf", + "#8f9bae", + "#8d99ad", + "#8b97ab", + "#8996aa", + "#8794a9", + "#8592a8", + "#8391a6", + "#818fa5", + "#7f8da4", + "#7d8ca3", + "#7b8aa1", + "#7a88a0", + "#78879f", + "#76859e", + "#74839d", + "#72829b", + "#70809a", + "#6e7e99", + "#6c7d98", + "#6a7b97", + "#687a96", + "#677895", + "#657694", + "#637592", + "#617391", + "#5f7290", + "#5d708f", + "#5b6e8e", + "#5a6d8d", + "#586b8c", + "#566a8b", + "#54688a", + "#526789", + "#506588", + "#4e6387", + "#4c6286", + "#4b6085", + "#495f84", + "#475d83", + "#455c81", + "#435a80", + "#415980", + "#3f577f", + "#3e557e", + "#3c547d", + "#3a527c", + "#38517b", + "#364f7a", + "#344e79", + "#324c78", + "#304a77", + "#2e4976", + "#2c4775", + "#2a4674", + "#284473", + "#264372", + "#244171", + "#223f71", + "#203e70", + "#1e3c6f", + "#1c3a6e", + "#1a396d", + "#17376c", + "#15356c", + "#12346b", + "#10326a", + "#0d3069", + "#0a2e69", + "#072d68", + "#052b67", + "#022967", + "#002766", + ], + "flex_GrPu": [ + "#0f4424", + "#124526", + "#144727", + "#174829", + "#19492a", + "#1b4b2c", + "#1d4c2d", + "#1f4d2f", + "#214f30", + "#235032", + "#255234", + "#275335", + "#295437", + "#2b5638", + "#2d573a", + "#2f583b", + "#315a3d", + "#335b3e", + "#355c40", + "#365e42", + "#385f43", + "#3a6045", + "#3c6246", + "#3e6348", + "#3f644a", + "#41664b", + "#43674d", + "#45684e", + "#476a50", + "#486b52", + "#4a6c53", + "#4c6e55", + "#4e6f56", + "#4f7058", + "#51725a", + "#53735b", + "#55745d", + "#57765f", + "#587760", + "#5a7962", + "#5c7a63", + "#5e7b65", + "#5f7d67", + "#617e68", + "#637f6a", + "#65816c", + "#67826d", + "#68846f", + "#6a8571", + "#6c8672", + "#6e8874", + "#6f8976", + "#718b78", + "#738c79", + "#758e7b", + "#778f7d", + "#79907e", + "#7a9280", + "#7c9382", + "#7e9584", + "#809685", + "#829887", + "#849989", + "#859b8b", + "#879c8c", + "#899d8e", + "#8b9f90", + "#8da092", + "#8fa294", + "#91a395", + "#92a597", + "#94a699", + "#96a89b", + "#98aa9d", + "#9aab9e", + "#9cada0", + "#9eaea2", + "#a0b0a4", + "#a2b1a6", + "#a4b3a8", + "#a6b4aa", + "#a8b6ab", + "#aab8ad", + "#acb9af", + "#aebbb1", + "#b0bcb3", + "#b2beb5", + "#b4c0b7", + "#b6c1b9", + "#b8c3bb", + "#bac5bd", + "#bcc6bf", + "#bec8c1", + "#c0cac2", + "#c2cbc4", + "#c4cdc6", + "#c6cfc8", + "#c8d0ca", + "#cad2cc", + "#ccd4ce", + "#ced6d0", + "#d0d7d2", + "#d3d9d5", + "#d5dbd7", + "#d7ddd9", + "#d9dfdb", + "#dbe0dd", + "#dde2df", + "#dfe4e1", + "#e2e6e3", + "#e4e8e5", + "#e6eae7", + "#e8ebe9", + "#ebedeb", + "#edefee", + "#eff1f0", + "#f1f3f2", + "#f4f5f4", + "#f6f7f6", + "#f8f9f8", + "#fafbfb", + "#fdfdfd", + "#FFFFFF", + "#fdfdfd", + "#fbfbfc", + "#f9f9fa", + "#f7f7f8", + "#f5f5f7", + "#f3f3f5", + "#f1f0f4", + "#efeef2", + "#ececf0", + "#eaeaef", + "#e8e8ed", + "#e6e6ec", + "#e4e5ea", + "#e3e3e9", + "#e1e1e8", + "#dfdfe6", + "#dddde5", + "#dbdbe3", + "#d9d9e2", + "#d7d7e1", + "#d5d5df", + "#d3d3de", + "#d1d1dd", + "#cfd0db", + "#ceceda", + "#ccccd9", + "#cacad7", + "#c8c8d6", + "#c6c6d5", + "#c4c4d4", + "#c3c3d2", + "#c1c1d1", + "#bfbfd0", + "#bdbdcf", + "#bcbcce", + "#babacd", + "#b8b8cb", + "#b6b6ca", + "#b5b4c9", + "#b3b3c8", + "#b1b1c7", + "#afafc6", + "#aeaec5", + "#acacc4", + "#aaaac3", + "#a9a8c1", + "#a7a7c0", + "#a5a5bf", + "#a4a3be", + "#a2a2bd", + "#a1a0bc", + "#9f9ebb", + "#9d9dba", + "#9c9bb9", + "#9a99b8", + "#9898b8", + "#9796b7", + "#9594b6", + "#9493b5", + "#9291b4", + "#918fb3", + "#8f8eb2", + "#8e8cb1", + "#8c8ab0", + "#8b89af", + "#8987af", + "#8786ae", + "#8684ad", + "#8482ac", + "#8381ab", + "#817faa", + "#807eaa", + "#7f7ca9", + "#7d7aa8", + "#7c79a7", + "#7a77a6", + "#7976a6", + "#7774a5", + "#7672a4", + "#7471a4", + "#736fa3", + "#726ea2", + "#706ca1", + "#6f6aa1", + "#6d69a0", + "#6c679f", + "#6b669f", + "#69649e", + "#68629d", + "#67619d", + "#655f9c", + "#645e9c", + "#635c9b", + "#615a9a", + "#60599a", + "#5f5799", + "#5d5599", + "#5c5498", + "#5b5298", + "#595097", + "#584f97", + "#574d96", + "#564b96", + "#554a95", + "#534895", + "#524695", + "#514494", + "#504394", + "#4f4193", + "#4d3f93", + "#4c3d93", + "#4b3b92", + "#4a3992", + "#493792", + "#483592", + "#473392", + "#463191", + "#452f91", + "#442d91", + "#432a91", + "#422891", + "#412591", + ], + "flex_PuGr": [ + "#412591", + "#422891", + "#432a91", + "#442d91", + "#452f91", + "#463191", + "#473392", + "#483592", + "#493792", + "#4a3992", + "#4b3b92", + "#4c3d93", + "#4d3f93", + "#4f4193", + "#504394", + "#514494", + "#524695", + "#534895", + "#554a95", + "#564b96", + "#574d96", + "#584f97", + "#595097", + "#5b5298", + "#5c5498", + "#5d5599", + "#5f5799", + "#60599a", + "#615a9a", + "#635c9b", + "#645e9c", + "#655f9c", + "#67619d", + "#68629d", + "#69649e", + "#6b669f", + "#6c679f", + "#6d69a0", + "#6f6aa1", + "#706ca1", + "#726ea2", + "#736fa3", + "#7471a4", + "#7672a4", + "#7774a5", + "#7976a6", + "#7a77a6", + "#7c79a7", + "#7d7aa8", + "#7f7ca9", + "#807eaa", + "#817faa", + "#8381ab", + "#8482ac", + "#8684ad", + "#8786ae", + "#8987af", + "#8b89af", + "#8c8ab0", + "#8e8cb1", + "#8f8eb2", + "#918fb3", + "#9291b4", + "#9493b5", + "#9594b6", + "#9796b7", + "#9898b8", + "#9a99b8", + "#9c9bb9", + "#9d9dba", + "#9f9ebb", + "#a1a0bc", + "#a2a2bd", + "#a4a3be", + "#a5a5bf", + "#a7a7c0", + "#a9a8c1", + "#aaaac3", + "#acacc4", + "#aeaec5", + "#afafc6", + "#b1b1c7", + "#b3b3c8", + "#b5b4c9", + "#b6b6ca", + "#b8b8cb", + "#babacd", + "#bcbcce", + "#bdbdcf", + "#bfbfd0", + "#c1c1d1", + "#c3c3d2", + "#c4c4d4", + "#c6c6d5", + "#c8c8d6", + "#cacad7", + "#ccccd9", + "#ceceda", + "#cfd0db", + "#d1d1dd", + "#d3d3de", + "#d5d5df", + "#d7d7e1", + "#d9d9e2", + "#dbdbe3", + "#dddde5", + "#dfdfe6", + "#e1e1e8", + "#e3e3e9", + "#e4e5ea", + "#e6e6ec", + "#e8e8ed", + "#eaeaef", + "#ececf0", + "#efeef2", + "#f1f0f4", + "#f3f3f5", + "#f5f5f7", + "#f7f7f8", + "#f9f9fa", + "#fbfbfc", + "#fdfdfd", + "#FFFFFF", + "#fdfdfd", + "#fafbfb", + "#f8f9f8", + "#f6f7f6", + "#f4f5f4", + "#f1f3f2", + "#eff1f0", + "#edefee", + "#ebedeb", + "#e8ebe9", + "#e6eae7", + "#e4e8e5", + "#e2e6e3", + "#dfe4e1", + "#dde2df", + "#dbe0dd", + "#d9dfdb", + "#d7ddd9", + "#d5dbd7", + "#d3d9d5", + "#d0d7d2", + "#ced6d0", + "#ccd4ce", + "#cad2cc", + "#c8d0ca", + "#c6cfc8", + "#c4cdc6", + "#c2cbc4", + "#c0cac2", + "#bec8c1", + "#bcc6bf", + "#bac5bd", + "#b8c3bb", + "#b6c1b9", + "#b4c0b7", + "#b2beb5", + "#b0bcb3", + "#aebbb1", + "#acb9af", + "#aab8ad", + "#a8b6ab", + "#a6b4aa", + "#a4b3a8", + "#a2b1a6", + "#a0b0a4", + "#9eaea2", + "#9cada0", + "#9aab9e", + "#98aa9d", + "#96a89b", + "#94a699", + "#92a597", + "#91a395", + "#8fa294", + "#8da092", + "#8b9f90", + "#899d8e", + "#879c8c", + "#859b8b", + "#849989", + "#829887", + "#809685", + "#7e9584", + "#7c9382", + "#7a9280", + "#79907e", + "#778f7d", + "#758e7b", + "#738c79", + "#718b78", + "#6f8976", + "#6e8874", + "#6c8672", + "#6a8571", + "#68846f", + "#67826d", + "#65816c", + "#637f6a", + "#617e68", + "#5f7d67", + "#5e7b65", + "#5c7a63", + "#5a7962", + "#587760", + "#57765f", + "#55745d", + "#53735b", + "#51725a", + "#4f7058", + "#4e6f56", + "#4c6e55", + "#4a6c53", + "#486b52", + "#476a50", + "#45684e", + "#43674d", + "#41664b", + "#3f644a", + "#3e6348", + "#3c6246", + "#3a6045", + "#385f43", + "#365e42", + "#355c40", + "#335b3e", + "#315a3d", + "#2f583b", + "#2d573a", + "#2b5638", + "#295437", + "#275335", + "#255234", + "#235032", + "#214f30", + "#1f4d2f", + "#1d4c2d", + "#1b4b2c", + "#19492a", + "#174829", + "#144727", + "#124526", + "#0f4424", + ], + "flex_TuOr": [ + "#134e4a", + "#164f4b", + "#19504d", + "#1b524e", + "#1e534f", + "#205450", + "#225552", + "#255753", + "#275854", + "#295955", + "#2b5a57", + "#2d5c58", + "#2f5d59", + "#315e5a", + "#335f5c", + "#35615d", + "#37625e", + "#39635f", + "#3b6461", + "#3c6662", + "#3e6763", + "#406865", + "#426966", + "#446b67", + "#456c68", + "#476d6a", + "#496e6b", + "#4b706c", + "#4d716e", + "#4e726f", + "#507370", + "#527572", + "#547673", + "#557774", + "#577975", + "#597a77", + "#5b7b78", + "#5d7c79", + "#5e7e7b", + "#607f7c", + "#62807d", + "#64827f", + "#658380", + "#678482", + "#698683", + "#6b8784", + "#6c8886", + "#6e8a87", + "#708b88", + "#728c8a", + "#738e8b", + "#758f8c", + "#77908e", + "#79928f", + "#7a9391", + "#7c9492", + "#7e9693", + "#809795", + "#819896", + "#839a98", + "#859b99", + "#879d9b", + "#899e9c", + "#8a9f9d", + "#8ca19f", + "#8ea2a0", + "#90a4a2", + "#92a5a3", + "#93a7a5", + "#95a8a6", + "#97a9a8", + "#99aba9", + "#9bacab", + "#9daeac", + "#9eafae", + "#a0b1af", + "#a2b2b1", + "#a4b4b2", + "#a6b5b4", + "#a8b7b5", + "#aab8b7", + "#acbab8", + "#adbbba", + "#afbdbb", + "#b1bebd", + "#b3c0bf", + "#b5c1c0", + "#b7c3c2", + "#b9c5c3", + "#bbc6c5", + "#bdc8c7", + "#bfc9c8", + "#c1cbca", + "#c3cccc", + "#c5cecd", + "#c7d0cf", + "#c9d1d1", + "#cbd3d2", + "#cdd5d4", + "#cfd6d6", + "#d1d8d7", + "#d3dad9", + "#d5dbdb", + "#d7dddc", + "#d9dfde", + "#dbe0e0", + "#dde2e2", + "#dfe4e3", + "#e1e6e5", + "#e3e7e7", + "#e5e9e9", + "#e7ebeb", + "#e9edec", + "#ebeeee", + "#eef0f0", + "#f0f2f2", + "#f2f4f4", + "#f4f6f6", + "#f6f8f7", + "#f8f9f9", + "#fbfbfb", + "#fdfdfd", + "#FFFFFF", + "#fefdfd", + "#fcfcfb", + "#fbfaf9", + "#faf8f7", + "#f9f7f6", + "#f7f5f4", + "#f6f4f2", + "#f5f2f0", + "#f4f0ee", + "#f2efec", + "#f1edea", + "#f0ece8", + "#efeae6", + "#eee8e4", + "#ede7e2", + "#ece5df", + "#ebe4dd", + "#eae2db", + "#e9e0d9", + "#e8dfd7", + "#e7ddd5", + "#e6dcd3", + "#e5dad1", + "#e5d8cf", + "#e4d7cd", + "#e3d5cb", + "#e2d4c9", + "#e1d2c7", + "#e0d0c5", + "#dfcfc3", + "#dfcdc1", + "#deccbe", + "#ddcabc", + "#dcc9ba", + "#dbc7b8", + "#dac6b6", + "#dac4b4", + "#d9c2b2", + "#d8c1b0", + "#d7bfae", + "#d6beac", + "#d6bcaa", + "#d5bba8", + "#d4b9a6", + "#d3b8a4", + "#d3b6a2", + "#d2b5a0", + "#d1b39e", + "#d0b29c", + "#d0b09a", + "#cfaf98", + "#cead96", + "#cdac94", + "#cdaa92", + "#cca990", + "#cba78e", + "#caa68c", + "#caa48a", + "#c9a388", + "#c8a286", + "#c7a084", + "#c79f82", + "#c69d80", + "#c59c7e", + "#c59a7c", + "#c4997a", + "#c39778", + "#c29676", + "#c29474", + "#c19372", + "#c09270", + "#c0906e", + "#bf8f6c", + "#be8d6b", + "#bd8c69", + "#bd8a67", + "#bc8965", + "#bb8863", + "#bb8661", + "#ba855f", + "#b9835d", + "#b8825b", + "#b88059", + "#b77f57", + "#b67e55", + "#b57c53", + "#b57b51", + "#b47950", + "#b3784e", + "#b3774c", + "#b2754a", + "#b17448", + "#b07246", + "#b07144", + "#af7042", + "#ae6e40", + "#ad6d3e", + "#ad6b3c", + "#ac6a3a", + "#ab6938", + "#aa6737", + "#a96635", + "#a96433", + "#a86331", + "#a7622f", + "#a6602d", + "#a65f2b", + "#a55d29", + "#a45c27", + "#a35b25", + "#a25923", + "#a15821", + "#a1571f", + "#a0551c", + "#9f541a", + "#9e5218", + "#9d5116", + "#9c5013", + "#9c4e11", + "#9b4d0e", + "#9a4b0b", + "#994a08", + ], + "flex_OrTu": [ + "#994a08", + "#9a4b0b", + "#9b4d0e", + "#9c4e11", + "#9c5013", + "#9d5116", + "#9e5218", + "#9f541a", + "#a0551c", + "#a1571f", + "#a15821", + "#a25923", + "#a35b25", + "#a45c27", + "#a55d29", + "#a65f2b", + "#a6602d", + "#a7622f", + "#a86331", + "#a96433", + "#a96635", + "#aa6737", + "#ab6938", + "#ac6a3a", + "#ad6b3c", + "#ad6d3e", + "#ae6e40", + "#af7042", + "#b07144", + "#b07246", + "#b17448", + "#b2754a", + "#b3774c", + "#b3784e", + "#b47950", + "#b57b51", + "#b57c53", + "#b67e55", + "#b77f57", + "#b88059", + "#b8825b", + "#b9835d", + "#ba855f", + "#bb8661", + "#bb8863", + "#bc8965", + "#bd8a67", + "#bd8c69", + "#be8d6b", + "#bf8f6c", + "#c0906e", + "#c09270", + "#c19372", + "#c29474", + "#c29676", + "#c39778", + "#c4997a", + "#c59a7c", + "#c59c7e", + "#c69d80", + "#c79f82", + "#c7a084", + "#c8a286", + "#c9a388", + "#caa48a", + "#caa68c", + "#cba78e", + "#cca990", + "#cdaa92", + "#cdac94", + "#cead96", + "#cfaf98", + "#d0b09a", + "#d0b29c", + "#d1b39e", + "#d2b5a0", + "#d3b6a2", + "#d3b8a4", + "#d4b9a6", + "#d5bba8", + "#d6bcaa", + "#d6beac", + "#d7bfae", + "#d8c1b0", + "#d9c2b2", + "#dac4b4", + "#dac6b6", + "#dbc7b8", + "#dcc9ba", + "#ddcabc", + "#deccbe", + "#dfcdc1", + "#dfcfc3", + "#e0d0c5", + "#e1d2c7", + "#e2d4c9", + "#e3d5cb", + "#e4d7cd", + "#e5d8cf", + "#e5dad1", + "#e6dcd3", + "#e7ddd5", + "#e8dfd7", + "#e9e0d9", + "#eae2db", + "#ebe4dd", + "#ece5df", + "#ede7e2", + "#eee8e4", + "#efeae6", + "#f0ece8", + "#f1edea", + "#f2efec", + "#f4f0ee", + "#f5f2f0", + "#f6f4f2", + "#f7f5f4", + "#f9f7f6", + "#faf8f7", + "#fbfaf9", + "#fcfcfb", + "#fefdfd", + "#FFFFFF", + "#fdfdfd", + "#fbfbfb", + "#f8f9f9", + "#f6f8f7", + "#f4f6f6", + "#f2f4f4", + "#f0f2f2", + "#eef0f0", + "#ebeeee", + "#e9edec", + "#e7ebeb", + "#e5e9e9", + "#e3e7e7", + "#e1e6e5", + "#dfe4e3", + "#dde2e2", + "#dbe0e0", + "#d9dfde", + "#d7dddc", + "#d5dbdb", + "#d3dad9", + "#d1d8d7", + "#cfd6d6", + "#cdd5d4", + "#cbd3d2", + "#c9d1d1", + "#c7d0cf", + "#c5cecd", + "#c3cccc", + "#c1cbca", + "#bfc9c8", + "#bdc8c7", + "#bbc6c5", + "#b9c5c3", + "#b7c3c2", + "#b5c1c0", + "#b3c0bf", + "#b1bebd", + "#afbdbb", + "#adbbba", + "#acbab8", + "#aab8b7", + "#a8b7b5", + "#a6b5b4", + "#a4b4b2", + "#a2b2b1", + "#a0b1af", + "#9eafae", + "#9daeac", + "#9bacab", + "#99aba9", + "#97a9a8", + "#95a8a6", + "#93a7a5", + "#92a5a3", + "#90a4a2", + "#8ea2a0", + "#8ca19f", + "#8a9f9d", + "#899e9c", + "#879d9b", + "#859b99", + "#839a98", + "#819896", + "#809795", + "#7e9693", + "#7c9492", + "#7a9391", + "#79928f", + "#77908e", + "#758f8c", + "#738e8b", + "#728c8a", + "#708b88", + "#6e8a87", + "#6c8886", + "#6b8784", + "#698683", + "#678482", + "#658380", + "#64827f", + "#62807d", + "#607f7c", + "#5e7e7b", + "#5d7c79", + "#5b7b78", + "#597a77", + "#577975", + "#557774", + "#547673", + "#527572", + "#507370", + "#4e726f", + "#4d716e", + "#4b706c", + "#496e6b", + "#476d6a", + "#456c68", + "#446b67", + "#426966", + "#406865", + "#3e6763", + "#3c6662", + "#3b6461", + "#39635f", + "#37625e", + "#35615d", + "#335f5c", + "#315e5a", + "#2f5d59", + "#2d5c58", + "#2b5a57", + "#295955", + "#275854", + "#255753", + "#225552", + "#205450", + "#1e534f", + "#1b524e", + "#19504d", + "#164f4b", + "#134e4a", + ], +} diff --git a/tidy3d/components/viz/flex_style.py b/tidy3d/components/viz/flex_style.py new file mode 100644 index 0000000000..f2ced3a407 --- /dev/null +++ b/tidy3d/components/viz/flex_style.py @@ -0,0 +1,46 @@ +from __future__ import annotations + +from tidy3d.log import log + +_ORIGINAL_PARAMS = None + + +def apply_tidy3d_params(): + """ + Applies a set of defaults to the matplotlib params that are following the tidy3d color palettes and design. + """ + global _ORIGINAL_PARAMS + try: + import matplotlib as mpl + import matplotlib.pyplot as plt + + _ORIGINAL_PARAMS = mpl.rcParams.copy() + + try: + plt.style.use("tidy3d.style") + except Exception as e: + log.error(f"Failed to apply Tidy3D plotting style on import. Error: {e}") + _ORIGINAL_PARAMS = {} + except ImportError: + pass + + +def restore_matplotlib_rcparams(): + """ + Resets matplotlib rcParams to the values they had before the Tidy3D + style was automatically applied on import. + """ + global _ORIGINAL_PARAMS + try: + import matplotlib.pyplot as plt + from matplotlib import style + + if not _ORIGINAL_PARAMS: + style.use("default") + return + + plt.rcParams.update(_ORIGINAL_PARAMS) + except ImportError: + log.error("Matplotlib is not installed on your system. Failed to reset to default styles.") + except Exception as e: + log.error(f"Failed to reset previous Matplotlib style. Error: {e}") diff --git a/tidy3d/components/viz/plot_params.py b/tidy3d/components/viz/plot_params.py new file mode 100644 index 0000000000..76b22b0ef6 --- /dev/null +++ b/tidy3d/components/viz/plot_params.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from typing import Any + +import pydantic.v1 as pd +from numpy import inf + +from tidy3d.components.base import Tidy3dBaseModel + + +class AbstractPlotParams(Tidy3dBaseModel): + """Abstract class for storing plotting parameters. + Corresponds with select properties of ``matplotlib.artist.Artist``. + """ + + alpha: Any = pd.Field(1.0, title="Opacity") + zorder: float = pd.Field(None, title="Display Order") + + def include_kwargs(self, **kwargs) -> AbstractPlotParams: + """Update the plot params with supplied kwargs.""" + update_dict = { + key: value + for key, value in kwargs.items() + if key not in ("type",) and value is not None and key in self.__fields__ + } + return self.copy(update=update_dict) + + def override_with_viz_spec(self, viz_spec) -> AbstractPlotParams: + """Override plot params with supplied VisualizationSpec.""" + return self.include_kwargs(**dict(viz_spec)) + + def to_kwargs(self) -> dict: + """Export the plot parameters as kwargs dict that can be supplied to plot function.""" + kwarg_dict = self.dict() + for ignore_key in ("type", "attrs"): + kwarg_dict.pop(ignore_key) + return kwarg_dict + + +class PathPlotParams(AbstractPlotParams): + """Stores plotting parameters / specifications for a path. + Corresponds with select properties of ``matplotlib.lines.Line2D``. + """ + + color: Any = pd.Field(None, title="Color", alias="c") + linewidth: pd.NonNegativeFloat = pd.Field(2, title="Line Width", alias="lw") + linestyle: str = pd.Field("--", title="Line Style", alias="ls") + marker: Any = pd.Field("o", title="Marker Style") + markeredgecolor: Any = pd.Field(None, title="Marker Edge Color", alias="mec") + markerfacecolor: Any = pd.Field(None, title="Marker Face Color", alias="mfc") + markersize: pd.NonNegativeFloat = pd.Field(10, title="Marker Size", alias="ms") + + +class PlotParams(AbstractPlotParams): + """Stores plotting parameters / specifications for a given model. + Corresponds with select properties of ``matplotlib.patches.Patch``. + """ + + edgecolor: Any = pd.Field(None, title="Edge Color", alias="ec") + facecolor: Any = pd.Field(None, title="Face Color", alias="fc") + fill: bool = pd.Field(True, title="Is Filled") + hatch: str = pd.Field(None, title="Hatch Style") + linewidth: pd.NonNegativeFloat = pd.Field(1, title="Line Width", alias="lw") + + +# defaults for different tidy3d objects +plot_params_geometry = PlotParams() +plot_params_structure = PlotParams() +plot_params_source = PlotParams(alpha=0.4, facecolor="limegreen", edgecolor="limegreen", lw=3) +plot_params_monitor = PlotParams(alpha=0.4, facecolor="orange", edgecolor="orange", lw=3) +plot_params_pml = PlotParams(alpha=0.7, facecolor="gray", edgecolor="gray", hatch="x", zorder=inf) +plot_params_pec = PlotParams(alpha=1.0, facecolor="gold", edgecolor="black", zorder=inf) +plot_params_pmc = PlotParams(alpha=1.0, facecolor="lightsteelblue", edgecolor="black", zorder=inf) +plot_params_bloch = PlotParams(alpha=1.0, facecolor="orchid", edgecolor="black", zorder=inf) +plot_params_symmetry = PlotParams(edgecolor="gray", facecolor="gray", alpha=0.6, zorder=inf) +plot_params_override_structures = PlotParams( + linewidth=0.4, edgecolor="black", fill=False, zorder=inf +) +plot_params_fluid = PlotParams(facecolor="white", edgecolor="lightsteelblue", lw=0.4, hatch="xx") +plot_params_grid = PlotParams(edgecolor="black", lw=0.2) +plot_params_lumped_element = PlotParams( + alpha=0.4, facecolor="mediumblue", edgecolor="mediumblue", lw=3 +) diff --git a/tidy3d/components/viz/plot_sim_3d.py b/tidy3d/components/viz/plot_sim_3d.py new file mode 100644 index 0000000000..46cf50c256 --- /dev/null +++ b/tidy3d/components/viz/plot_sim_3d.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from html import escape + +from tidy3d.exceptions import SetupError + + +def plot_sim_3d(sim, width=800, height=800) -> None: + """Make 3D display of simulation in ipyython notebook.""" + + try: + from IPython.display import HTML, display + except ImportError as e: + raise SetupError( + "3D plotting requires ipython to be installed " + "and the code to be running on a jupyter notebook." + ) from e + + from base64 import b64encode + from io import BytesIO + + buffer = BytesIO() + sim.to_hdf5_gz(buffer) + buffer.seek(0) + base64 = b64encode(buffer.read()).decode("utf-8") + js_code = """ + /** + * Simulation Viewer Injector + * + * Monitors the document for elements being added in the form: + * + *
+ * + * This script will then inject an iframe to the viewer application, and pass it the simulation data + * via the postMessage API on request. The script may be safely included multiple times, with only the + * configuration of the first started script (e.g. viewer URL) applying. + * + */ + (function() { + const TARGET_CLASS = "simulation-viewer"; + const ACTIVE_CLASS = "simulation-viewer-active"; + const VIEWER_URL = "https://tidy3d.simulation.cloud/simulation-viewer"; + + class SimulationViewerInjector { + constructor() { + for (var node of document.getElementsByClassName(TARGET_CLASS)) { + this.injectViewer(node); + } + + // Monitor for newly added nodes to the DOM + this.observer = new MutationObserver(this.onMutations.bind(this)); + this.observer.observe(document.body, {childList: true, subtree: true}); + } + + onMutations(mutations) { + for (var mutation of mutations) { + if (mutation.type === 'childList') { + /** + * Have found that adding the element does not reliably trigger the mutation observer. + * It may be the case that setting content with innerHTML does not trigger. + * + * It seems to be sufficient to re-scan the document for un-activated viewers + * whenever an event occurs, as Jupyter triggers multiple events on cell evaluation. + */ + var viewers = document.getElementsByClassName(TARGET_CLASS); + for (var node of viewers) { + this.injectViewer(node); + } + } + } + } + + injectViewer(node) { + // (re-)check that this is a valid simulation container and has not already been injected + if (node.classList.contains(TARGET_CLASS) && !node.classList.contains(ACTIVE_CLASS)) { + // Mark node as injected, to prevent re-runs + node.classList.add(ACTIVE_CLASS); + + var uuid; + if (window.crypto && window.crypto.randomUUID) { + uuid = window.crypto.randomUUID(); + } else { + uuid = "" + Math.random(); + } + + var frame = document.createElement("iframe"); + frame.width = node.dataset.width || 800; + frame.height = node.dataset.height || 800; + frame.style.cssText = `width:${frame.width}px;height:${frame.height}px;max-width:none;border:0;display:block` + frame.src = VIEWER_URL + "?uuid=" + uuid; + + var postMessageToViewer; + postMessageToViewer = event => { + if(event.data.type === 'viewer' && event.data.uuid===uuid){ + frame.contentWindow.postMessage({ type: 'jupyter', uuid, value: node.dataset.simulation, fileType: 'hdf5'}, '*'); + + // Run once only + window.removeEventListener('message', postMessageToViewer); + } + }; + window.addEventListener( + 'message', + postMessageToViewer, + false + ); + + node.appendChild(frame); + } + } + } + + if (!window.simulationViewerInjector) { + window.simulationViewerInjector = new SimulationViewerInjector(); + } + })(); + """ + html_code = f""" +
+ + """ + + return display(HTML(html_code)) diff --git a/tidy3d/components/viz/styles.py b/tidy3d/components/viz/styles.py new file mode 100644 index 0000000000..5fd806e65f --- /dev/null +++ b/tidy3d/components/viz/styles.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +try: + from matplotlib.patches import ArrowStyle + + arrow_style = ArrowStyle.Simple(head_length=11, head_width=9, tail_width=4) +except ImportError: + arrow_style = None + +FLEXCOMPUTE_COLORS = { + "brand_green": "#00643C", + "brand_tan": "#B8A18B", + "brand_blue": "#6DB5DD", + "brand_purple": "#8851AD", + "brand_black": "#000000", + "brand_orange": "#FC7A4C", +} +ARROW_COLOR_SOURCE = FLEXCOMPUTE_COLORS["brand_green"] +ARROW_COLOR_POLARIZATION = FLEXCOMPUTE_COLORS["brand_tan"] +ARROW_COLOR_MONITOR = FLEXCOMPUTE_COLORS["brand_orange"] +PLOT_BUFFER = 0.3 +ARROW_ALPHA = 0.8 +ARROW_LENGTH = 0.3 + +# stores color of simulation.structures for given index in simulation.medium_map +MEDIUM_CMAP = [ + "#689DBC", + "#D0698E", + "#5E6EAD", + "#C6224E", + "#BDB3E2", + "#9EC3E0", + "#616161", + "#877EBC", +] + +# colormap for structure's permittivity in plot_eps +STRUCTURE_EPS_CMAP = "gist_yarg" +STRUCTURE_EPS_CMAP_R = "gist_yarg_r" +STRUCTURE_HEAT_COND_CMAP = "gist_yarg" diff --git a/tidy3d/components/viz/visualization_spec.py b/tidy3d/components/viz/visualization_spec.py new file mode 100644 index 0000000000..abe22ed7cf --- /dev/null +++ b/tidy3d/components/viz/visualization_spec.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from typing import Any, Optional + +import pydantic.v1 as pd + +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.log import log + +MATPLOTLIB_IMPORTED = True +try: + from matplotlib.colors import is_color_like +except ImportError: + is_color_like = None + MATPLOTLIB_IMPORTED = False + + +def is_valid_color(value: str) -> str: + if not MATPLOTLIB_IMPORTED: + log.warning( + "matplotlib was not successfully imported, but is required " + "to validate colors in the VisualizationSpec. The specified colors " + "have not been validated." + ) + else: + if is_color_like is not None and not is_color_like(value): + raise ValueError(f"{value} is not a valid plotting color") + + return value + + +class VisualizationSpec(Tidy3dBaseModel): + """Defines specification for visualization when used with plotting functions.""" + + facecolor: str = pd.Field( + "", + title="Face color", + description="Color applied to the faces in visualization.", + ) + + edgecolor: Optional[str] = pd.Field( + "", + title="Edge color", + description="Color applied to the edges in visualization.", + ) + + alpha: Optional[pd.confloat(ge=0.0, le=1.0)] = pd.Field( + 1.0, + title="Opacity", + description="Opacity/alpha value in plotting between 0 and 1.", + ) + + @pd.validator("facecolor", always=True) + def validate_color(value: str) -> str: + return is_valid_color(value) + + @pd.validator("edgecolor", always=True) + def validate_and_copy_color(value: str, values: dict[str, Any]) -> str: + if (value == "") and "facecolor" in values: + return is_valid_color(values["facecolor"]) + + return is_valid_color(value) diff --git a/tidy3d/config.py b/tidy3d/config.py index 3598bc27a7..5dcf9989ea 100644 --- a/tidy3d/config.py +++ b/tidy3d/config.py @@ -1,5 +1,9 @@ """Sets the configuration of the script, can be changed with `td.config.config_name = new_val`.""" +from __future__ import annotations + +from typing import Optional + import pydantic.v1 as pd from .log import DEFAULT_LEVEL, LogLevel, set_log_suppression, set_logging_level @@ -33,6 +37,13 @@ class Config: "for several elements.", ) + use_local_subpixel: Optional[bool] = pd.Field( + False, + title="Whether to use local subpixel averaging. If 'None', local subpixel " + "averaging will be used if 'tidy3d-extras' is installed and not used otherwise. " + "NOTE: This feature is not yet supported.", + ) + @pd.validator("logging_level", pre=True, always=True) def _set_logging_level(cls, val): """Set the logging level if logging_level is changed.""" diff --git a/tidy3d/constants.py b/tidy3d/constants.py index 73c93b6cd4..7edcf22278 100644 --- a/tidy3d/constants.py +++ b/tidy3d/constants.py @@ -10,6 +10,8 @@ Q_e (float): funamental charge [C] """ +from __future__ import annotations + from types import MappingProxyType import numpy as np @@ -194,6 +196,11 @@ Joules per (kilogram Kelvin). """ +DENSITY = "kg/um^3" +""" +Kilograms per cubic micrometer. +""" + HEAT_FLUX = "W/um^2" """ Watts per square micrometer. diff --git a/tidy3d/exceptions.py b/tidy3d/exceptions.py index 32ccc88e49..96b137d749 100644 --- a/tidy3d/exceptions.py +++ b/tidy3d/exceptions.py @@ -1,12 +1,16 @@ """Custom Tidy3D exceptions""" +from __future__ import annotations + +from typing import Optional + from .log import log class Tidy3dError(ValueError): """Any error in tidy3d""" - def __init__(self, message: str = None): + def __init__(self, message: Optional[str] = None): """Log just the error message and then raise the Exception.""" super().__init__(message) log.error(message) diff --git a/tidy3d/log.py b/tidy3d/log.py index 9bbb0e04be..3cfa825773 100644 --- a/tidy3d/log.py +++ b/tidy3d/log.py @@ -1,8 +1,11 @@ -"""Logging for Tidy3d.""" +"""Logging Configuration for Tidy3d.""" + +from __future__ import annotations import inspect +from contextlib import contextmanager from datetime import datetime -from typing import Callable, List, Tuple, Union +from typing import Callable, Optional, Union from rich.console import Console from rich.text import Text @@ -42,7 +45,7 @@ CONSOLE_WIDTH = 80 -def _default_log_level_format(level: str, message: str) -> Tuple[str, str]: +def _default_log_level_format(level: str, message: str) -> tuple[str, str]: """By default just return unformatted prefix and message.""" return level, message @@ -214,7 +217,7 @@ def _parse_warning_capture(self, current_loc, stack_item): new_loc = current_loc + list(field) else: # single field - new_loc = current_loc + [field] + new_loc = [*current_loc, field] # process current level warnings for level, msg, custom_loc in stack_item["messages"]: @@ -242,7 +245,7 @@ def _log( message: str, *args, log_once: bool = False, - custom_loc: List = None, + custom_loc: Optional[list] = None, capture: bool = True, ) -> None: """Distribute log messages to all handlers""" @@ -311,7 +314,7 @@ def warning( message: str, *args, log_once: bool = False, - custom_loc: List = None, + custom_loc: Optional[list] = None, capture: bool = True, ) -> None: """Log (message) % (args) at warning level""" @@ -442,3 +445,33 @@ def get_logging_console() -> Console: if "console" not in log.handlers: set_logging_console() return log.handlers["console"].console + + +class NoOpProgress: + """Dummy progress manager that doesn't show any output.""" + + def __enter__(self): + return self + + def __exit__(self, *args, **kwargs): + pass + + def add_task(self, *args, **kwargs): + pass + + def update(self, *args, **kwargs): + pass + + +@contextmanager +def Progress(console, show_progress): + """Progress manager that wraps ``rich.Progress`` if ``show_progress`` is ``True``, + and ``NoOpProgress`` otherwise.""" + if show_progress: + from rich.progress import Progress + + with Progress(console=console) as progress: + yield progress + else: + with NoOpProgress() as progress: + yield progress diff --git a/tidy3d/material_library/material_library.py b/tidy3d/material_library/material_library.py index 18550e04cf..480f98ee8d 100644 --- a/tidy3d/material_library/material_library.py +++ b/tidy3d/material_library/material_library.py @@ -1,12 +1,16 @@ """Holds dispersive models for several commonly used optical materials.""" +from __future__ import annotations + import json -from typing import Dict, List, Union +from typing import Union import pydantic.v1 as pd +from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.material.multi_physics import MultiPhysicsMedium from tidy3d.components.material.tcad.charge import SemiconductorMedium +from tidy3d.components.medium import AnisotropicMedium, Medium2D, PoleResidue, Sellmeier from tidy3d.components.tcad.types import ( AugerRecombination, CaugheyThomasMobility, @@ -14,12 +18,10 @@ ShockleyReedHallRecombination, SlotboomBandGapNarrowing, ) +from tidy3d.components.types import Axis +from tidy3d.exceptions import SetupError +from tidy3d.log import log -from ..components.base import Tidy3dBaseModel -from ..components.medium import AnisotropicMedium, Medium2D, PoleResidue, Sellmeier -from ..components.types import Axis -from ..exceptions import SetupError -from ..log import log from .material_reference import ReferenceData, material_refs from .parametric_materials import Graphene from .util import ( @@ -66,7 +68,7 @@ def export_matlib_to_file(fname: str = "matlib.json") -> None: class AbstractVariantItem(Tidy3dBaseModel): """Reference, and data_source for a variant of a material.""" - reference: List[ReferenceData] = pd.Field( + reference: list[ReferenceData] = pd.Field( None, title="Reference information", description="A list of references related to this variant model.", @@ -80,7 +82,7 @@ class AbstractVariantItem(Tidy3dBaseModel): ) @property - def summarize_mediums(self) -> Dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: + def summarize_mediums(self) -> dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: return {} def __str__(self): @@ -103,7 +105,7 @@ class VariantItem(AbstractVariantItem): ) @property - def summarize_mediums(self) -> Dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: + def summarize_mediums(self) -> dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: return {"medium": self.medium} @@ -111,7 +113,7 @@ class MaterialItem(Tidy3dBaseModel): """A material that includes several variants.""" name: str = pd.Field(..., title="Name", description="Unique name for the medium.") - variants: Dict[str, VariantItem] = pd.Field( + variants: dict[str, VariantItem] = pd.Field( ..., title="Dictionary of available variants for this material", description="A dictionary of available variants for this material " @@ -167,14 +169,14 @@ class VariantItem2D(AbstractVariantItem): ) @property - def summarize_mediums(self) -> Dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: + def summarize_mediums(self) -> dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: return {"medium": self.medium} class MaterialItem2D(MaterialItem): """A 2D material that includes several variants.""" - variants: Dict[str, VariantItem2D] = pd.Field( + variants: dict[str, VariantItem2D] = pd.Field( ..., title="Dictionary of available variants for this material", description="A dictionary of available variants for this material " @@ -213,19 +215,19 @@ def medium(self, optical_axis: Axis) -> AnisotropicMedium: """ components = ["xx", "yy", "zz"] - mat_dict = {comp: self.ordinary for comp in components} + mat_dict = dict.fromkeys(components, self.ordinary) mat_dict.update({components[optical_axis]: self.extraordinary}) return AnisotropicMedium.parse_obj(mat_dict) @property - def summarize_mediums(self) -> Dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: + def summarize_mediums(self) -> dict[str, Union[PoleResidue, Medium2D, MultiPhysicsMedium]]: return {"ordinary": self.ordinary, "extraordinary": self.extraordinary} class MaterialItemUniaxial(MaterialItem): """A material that includes several variants.""" - variants: Dict[str, VariantItemUniaxial] = pd.Field( + variants: dict[str, VariantItemUniaxial] = pd.Field( ..., title="Dictionary of available variants for this material", description="A dictionary of available variants for this material " @@ -352,8 +354,7 @@ def medium(self, optical_axis: Axis): frequency_range=(154771532566312.25, 1595489401708072.2), ), reference=[material_refs["Yang2015"]], - data_url="https://refractiveindex.info/data_csv.php?datafile=database/data-nk/" - "main/Ag/Yang.yml", + data_url="https://refractiveindex.info/data_csv.php?datafile=database/data-nk/main/Ag/Yang.yml", ) Al_Rakic1995 = VariantItem( @@ -1004,6 +1005,43 @@ def medium(self, optical_axis: Axis): reference=[material_refs["Palik_Lossy"]], ) +Ge_Nunley = VariantItem( + medium=PoleResidue( + name="Ge_Nunley", + eps_inf=1.0, + poles=[ + ( + (-1055692444928990.6 - 1.2069979211686232e16j), + (1107423663161164.6 - 3093285987380348.5j), + ), + ((-3216853350289244 - 8291440266759688j), (5700802820282152 + 2.5732993737266788e16j)), + ((-541881030908034.7 - 8791646324216410j), (-937105384931749 + 541020934229084.2j)), + ( + (-976547995477318.4 - 6543303598934721j), + (-1.0737211590127532e16 + 1.3992511131747758e16j), + ), + ((-284492778464386.2 - 6696785988114651j), (-2168480500787241.8 - 696493506373301.2j)), + ((-900354155072.7748 - 6663372533420019j), (183103725786.0085 - 141583942490.17123j)), + ((-7073535582440.927 - 6580195498223051j), (262790152.22284198 + 378843848585.63043j)), + ((-270911770733075.62 - 6447924271229311j), (1207997886295188 + 1471602437337227.5j)), + ((-255993466255361.62 - 5008805217676040j), (445613879952076.8 - 223801118798973.3j)), + ((-344512832764646.75 - 4858405095425429j), (563341672141455.9 + 1286782730502855.5j)), + ((-695769101918184.8 - 3620945512916543j), (5328924572609390 + 5529617018233712j)), + ((-252629750588162 - 3513125220372237.5j), (109779730682375.69 + 2230058891609707j)), + ( + (-141325408476762.66 - 3230461058493017.5j), + (126429312165475.8 + 1257642646101307.8j), + ), + ((-498950664609906.4 - 1179396998903782.5j), (180816169912939.7 - 297981189005482.4j)), + ((-37573278339073.01 - 1213096851555221.8j), (13359584691343.223 - 3071910249946.702j)), + ((-99651215401004 - 1635758773069449.5j), (5479484262079.737 - 6773804202146.6045j)), + ], + frequency_range=(1.209e14, 1.595e15), + ), + reference=[material_refs["Nunley2016"]], + data_url="https://refractiveindex.info/data_csv.php?datafile=database/data/main/Ge/nk/Nunley.yml", +) + GeOx_Horiba = VariantItem( medium=PoleResidue( name="GeOx_Horiba", @@ -2083,447 +2121,448 @@ def _repr_pretty_(self, p, cycle): material_library = MaterialLibrary( Ag=MaterialItem( name="Silver", - variants=dict( - Rakic1998BB=Ag_Rakic1998BB, - JohnsonChristy1972=Ag_JohnsonChristy1972, - RakicLorentzDrude1998=Ag_RakicLorentzDrude1998, - Yang2015Drude=Ag_Yang2015Drude, - ), + variants={ + "Rakic1998BB": Ag_Rakic1998BB, + "JohnsonChristy1972": Ag_JohnsonChristy1972, + "RakicLorentzDrude1998": Ag_RakicLorentzDrude1998, + "Yang2015Drude": Ag_Yang2015Drude, + }, default="Rakic1998BB", ), Al=MaterialItem( name="Aluminum", - variants=dict( - Rakic1995=Al_Rakic1995, - RakicLorentzDrude1998=Al_RakicLorentzDrude1998, - ), + variants={ + "Rakic1995": Al_Rakic1995, + "RakicLorentzDrude1998": Al_RakicLorentzDrude1998, + }, default="Rakic1995", ), Al2O3=MaterialItem( name="Alumina", - variants=dict( - Horiba=Al2O3_Horiba, - ), + variants={ + "Horiba": Al2O3_Horiba, + }, default="Horiba", ), AlAs=MaterialItem( name="Aluminum Arsenide", - variants=dict( - Horiba=AlAs_Horiba, - FernOnton1971=AlAs_FernOnton1971, - ), + variants={ + "Horiba": AlAs_Horiba, + "FernOnton1971": AlAs_FernOnton1971, + }, default="Horiba", ), AlGaN=MaterialItem( name="Aluminum Gallium Nitride", - variants=dict( - Horiba=AlGaN_Horiba, - ), + variants={ + "Horiba": AlGaN_Horiba, + }, default="Horiba", ), AlN=MaterialItem( name="Aluminum Nitride", - variants=dict( - Horiba=AlN_Horiba, - ), + variants={ + "Horiba": AlN_Horiba, + }, default="Horiba", ), AlxOy=MaterialItem( name="Aluminum Oxide", - variants=dict( - Horiba=AlxOy_Horiba, - ), + variants={ + "Horiba": AlxOy_Horiba, + }, default="Horiba", ), Aminoacid=MaterialItem( name="Amino Acid", - variants=dict( - Horiba=Aminoacid_Horiba, - ), + variants={ + "Horiba": Aminoacid_Horiba, + }, default="Horiba", ), Au=MaterialItem( name="Gold", - variants=dict( - Olmon2012crystal=Au_Olmon2012crystal, - Olmon2012stripped=Au_Olmon2012stripped, - Olmon2012evaporated=Au_Olmon2012evaporated, - Olmon2012Drude=Au_Olmon2012Drude, - JohnsonChristy1972=Au_JohnsonChristy1972, - RakicLorentzDrude1998=Au_RakicLorentzDrude1998, - ), + variants={ + "Olmon2012crystal": Au_Olmon2012crystal, + "Olmon2012stripped": Au_Olmon2012stripped, + "Olmon2012evaporated": Au_Olmon2012evaporated, + "Olmon2012Drude": Au_Olmon2012Drude, + "JohnsonChristy1972": Au_JohnsonChristy1972, + "RakicLorentzDrude1998": Au_RakicLorentzDrude1998, + }, default="Olmon2012evaporated", ), BK7=MaterialItem( name="N-BK7 Borosilicate Glass", - variants=dict( - Zemax=BK7_Zemax, - ), + variants={ + "Zemax": BK7_Zemax, + }, default="Zemax", ), Be=MaterialItem( name="Beryllium", - variants=dict( - Rakic1998BB=Be_Rakic1998BB, - RakicLorentzDrude1998=Be_RakicLorentzDrude1998, - ), + variants={ + "Rakic1998BB": Be_Rakic1998BB, + "RakicLorentzDrude1998": Be_RakicLorentzDrude1998, + }, default="Rakic1998BB", ), CaF2=MaterialItem( name="Calcium Fluoride", - variants=dict( - Horiba=CaF2_Horiba, - ), + variants={ + "Horiba": CaF2_Horiba, + }, default="Horiba", ), Cellulose=MaterialItem( name="Cellulose", - variants=dict( - Sultanova2009=Cellulose_Sultanova2009, - ), + variants={ + "Sultanova2009": Cellulose_Sultanova2009, + }, default="Sultanova2009", ), Cr=MaterialItem( name="Chromium", - variants=dict( - Rakic1998BB=Cr_Rakic1998BB, - RakicLorentzDrude1998=Cr_RakicLorentzDrude1998, - ), + variants={ + "Rakic1998BB": Cr_Rakic1998BB, + "RakicLorentzDrude1998": Cr_RakicLorentzDrude1998, + }, default="Rakic1998BB", ), Cu=MaterialItem( name="Copper", - variants=dict( - JohnsonChristy1972=Cu_JohnsonChristy1972, - RakicLorentzDrude1998=Cu_RakicLorentzDrude1998, - ), + variants={ + "JohnsonChristy1972": Cu_JohnsonChristy1972, + "RakicLorentzDrude1998": Cu_RakicLorentzDrude1998, + }, default="JohnsonChristy1972", ), FusedSilica=MaterialItem( name="Fused Silica", - variants=dict( - ZemaxSellmeier=FusedSilica_Zemax, - ZemaxVisiblePMLStable=FusedSilica_Zemax_Visible_PMLStable, - ZemaxPMLStable=FusedSilica_Zemax_PMLStable, - ), + variants={ + "ZemaxSellmeier": FusedSilica_Zemax, + "ZemaxVisiblePMLStable": FusedSilica_Zemax_Visible_PMLStable, + "ZemaxPMLStable": FusedSilica_Zemax_PMLStable, + }, default="ZemaxPMLStable", ), GaAs=MaterialItem( name="Gallium Arsenide", - variants=dict( - Palik_Lossless=GaAs_Palik_Lossless, - Palik_Lossy=GaAs_Palik_Lossy, - Skauli2003=GaAs_Skauli2003, - ), + variants={ + "Palik_Lossless": GaAs_Palik_Lossless, + "Palik_Lossy": GaAs_Palik_Lossy, + "Skauli2003": GaAs_Skauli2003, + }, default="Skauli2003", ), Ge=MaterialItem( name="Germanium", - variants=dict( - Palik_Lossless=Ge_Palik_Lossless, - Palik_Lossy=Ge_Palik_Lossy, - Icenogle1976=Ge_Icenogle1976, - ), + variants={ + "Palik_Lossless": Ge_Palik_Lossless, + "Palik_Lossy": Ge_Palik_Lossy, + "Icenogle1976": Ge_Icenogle1976, + "Nunley": Ge_Nunley, + }, default="Icenogle1976", ), GeOx=MaterialItem( name="Germanium Oxide", - variants=dict( - Horiba=GeOx_Horiba, - ), + variants={ + "Horiba": GeOx_Horiba, + }, default="Horiba", ), H2O=MaterialItem( name="Water", - variants=dict( - Horiba=H2O_Horiba, - ), + variants={ + "Horiba": H2O_Horiba, + }, default="Horiba", ), HMDS=MaterialItem( name="Hexamethyldisilazane, or Bis(trimethylsilyl)amine", - variants=dict( - Horiba=HMDS_Horiba, - ), + variants={ + "Horiba": HMDS_Horiba, + }, default="Horiba", ), HfO2=MaterialItem( name="Hafnium Oxide", - variants=dict( - Horiba=HfO2_Horiba, - ), + variants={ + "Horiba": HfO2_Horiba, + }, default="Horiba", ), ITO=MaterialItem( name="Indium Tin Oxide", - variants=dict( - Horiba=ITO_Horiba, - ), + variants={ + "Horiba": ITO_Horiba, + }, default="Horiba", ), InAs=MaterialItem( name="Indium Arsenide", - variants=dict( - Palik=InAs_Palik, - ), + variants={ + "Palik": InAs_Palik, + }, default="Palik", ), InP=MaterialItem( name="Indium Phosphide", - variants=dict( - Palik_Lossless=InP_Palik_Lossless, - Palik_Lossy=InP_Palik_Lossy, - Pettit1965=InP_Pettit1965, - ), + variants={ + "Palik_Lossless": InP_Palik_Lossless, + "Palik_Lossy": InP_Palik_Lossy, + "Pettit1965": InP_Pettit1965, + }, default="Pettit1965", ), MgF2=MaterialItem( name="Magnesium Fluoride", - variants=dict( - Horiba=MgF2_Horiba, - ), + variants={ + "Horiba": MgF2_Horiba, + }, default="Horiba", ), MgO=MaterialItem( name="Magnesium Oxide", - variants=dict( - StephensMalitson1952=MgO_StephensMalitson1952, - ), + variants={ + "StephensMalitson1952": MgO_StephensMalitson1952, + }, default="StephensMalitson1952", ), MoS2=MaterialItem2D( name="Molybdenum Disulfide", - variants=dict( - Li2014=MoS2_Li2014, - ), + variants={ + "Li2014": MoS2_Li2014, + }, default="Li2014", ), MoSe2=MaterialItem2D( name="Molybdenum Diselenide", - variants=dict( - Li2014=MoSe2_Li2014, - ), + variants={ + "Li2014": MoSe2_Li2014, + }, default="Li2014", ), Ni=MaterialItem( name="Nickel", - variants=dict( - JohnsonChristy1972=Ni_JohnsonChristy1972, - RakicLorentzDrude1998=Ni_RakicLorentzDrude1998, - ), + variants={ + "JohnsonChristy1972": Ni_JohnsonChristy1972, + "RakicLorentzDrude1998": Ni_RakicLorentzDrude1998, + }, default="JohnsonChristy1972", ), PEI=MaterialItem( name="Polyetherimide", - variants=dict( - Horiba=PEI_Horiba, - ), + variants={ + "Horiba": PEI_Horiba, + }, default="Horiba", ), PEN=MaterialItem( name="Polyethylene Naphthalate", - variants=dict( - Horiba=PEN_Horiba, - ), + variants={ + "Horiba": PEN_Horiba, + }, default="Horiba", ), PET=MaterialItem( name="Polyethylene Terephthalate", - variants=dict( - Horiba=PET_Horiba, - ), + variants={ + "Horiba": PET_Horiba, + }, default="Horiba", ), PMMA=MaterialItem( name="Poly(methyl Methacrylate)", - variants=dict( - Horiba=PMMA_Horiba, - Sultanova2009=PMMA_Sultanova2009, - ), + variants={ + "Horiba": PMMA_Horiba, + "Sultanova2009": PMMA_Sultanova2009, + }, default="Sultanova2009", ), PTFE=MaterialItem( name="Polytetrafluoroethylene, or Teflon", - variants=dict( - Horiba=PTFE_Horiba, - ), + variants={ + "Horiba": PTFE_Horiba, + }, default="Horiba", ), PVC=MaterialItem( name="Polyvinyl Chloride", - variants=dict( - Horiba=PVC_Horiba, - ), + variants={ + "Horiba": PVC_Horiba, + }, default="Horiba", ), Pd=MaterialItem( name="Palladium", - variants=dict( - JohnsonChristy1972=Pd_JohnsonChristy1972, - RakicLorentzDrude1998=Pd_RakicLorentzDrude1998, - ), + variants={ + "JohnsonChristy1972": Pd_JohnsonChristy1972, + "RakicLorentzDrude1998": Pd_RakicLorentzDrude1998, + }, default="JohnsonChristy1972", ), Polycarbonate=MaterialItem( name="Polycarbonate", - variants=dict( - Horiba=Polycarbonate_Horiba, - Sultanova2009=Polycarbonate_Sultanova2009, - ), + variants={ + "Horiba": Polycarbonate_Horiba, + "Sultanova2009": Polycarbonate_Sultanova2009, + }, default="Sultanova2009", ), Polystyrene=MaterialItem( name="Polystyrene", - variants=dict( - Sultanova2009=Polystyrene_Sultanova2009, - ), + variants={ + "Sultanova2009": Polystyrene_Sultanova2009, + }, default="Sultanova2009", ), Pt=MaterialItem( name="Platinum", - variants=dict( - Werner2009=Pt_Werner2009, - RakicLorentzDrude1998=Pt_RakicLorentzDrude1998, - ), + variants={ + "Werner2009": Pt_Werner2009, + "RakicLorentzDrude1998": Pt_RakicLorentzDrude1998, + }, default="Werner2009", ), Sapphire=MaterialItem( name="Sapphire", - variants=dict( - Horiba=Sapphire_Horiba, - ), + variants={ + "Horiba": Sapphire_Horiba, + }, default="Horiba", ), Si3N4=MaterialItem( name="Silicon Nitride", - variants=dict( - Horiba=Si3N4_Horiba, - Luke2015Sellmeier=Si3N4_Luke2015, - Luke2015PMLStable=Si3N4_Luke2015_PMLStable, - Philipp1973Sellmeier=Si3N4_Philipp1973, - ), + variants={ + "Horiba": Si3N4_Horiba, + "Luke2015Sellmeier": Si3N4_Luke2015, + "Luke2015PMLStable": Si3N4_Luke2015_PMLStable, + "Philipp1973Sellmeier": Si3N4_Philipp1973, + }, default="Horiba", ), SiC=MaterialItem( name="Silicon Carbide", - variants=dict( - Horiba=SiC_Horiba, - ), + variants={ + "Horiba": SiC_Horiba, + }, default="Horiba", ), SiN=MaterialItem( name="Silicon Mononitride", - variants=dict( - Horiba=SiN_Horiba, - ), + variants={ + "Horiba": SiN_Horiba, + }, default="Horiba", ), SiO2=MaterialItem( name="Silicon Dioxide", - variants=dict( - Palik_Lossless=SiO2_Palik_Lossless, - Palik_Lossy=SiO2_Palik_Lossy, - Horiba=SiO2_Horiba, - ), + variants={ + "Palik_Lossless": SiO2_Palik_Lossless, + "Palik_Lossy": SiO2_Palik_Lossy, + "Horiba": SiO2_Horiba, + }, default="Palik_Lossless", ), SiON=MaterialItem( name="Silicon Oxynitride", - variants=dict( - Horiba=SiON_Horiba, - ), + variants={ + "Horiba": SiON_Horiba, + }, default="Horiba", ), Ta2O5=MaterialItem( name="Tantalum Pentoxide", - variants=dict( - Horiba=Ta2O5_Horiba, - ), + variants={ + "Horiba": Ta2O5_Horiba, + }, default="Horiba", ), Ti=MaterialItem( name="Titanium", - variants=dict( - Werner2009=Ti_Werner2009, - RakicLorentzDrude1998=Ti_RakicLorentzDrude1998, - ), + variants={ + "Werner2009": Ti_Werner2009, + "RakicLorentzDrude1998": Ti_RakicLorentzDrude1998, + }, default="Werner2009", ), TiOx=MaterialItem( name="Titanium Oxide", - variants=dict( - Horiba=TiOx_Horiba, - HorbiaStable=TiOx_HoribaStable, - ), + variants={ + "Horiba": TiOx_Horiba, + "HorbiaStable": TiOx_HoribaStable, + }, default="Horiba", ), W=MaterialItem( name="Tungsten", - variants=dict( - Werner2009=W_Werner2009, - RakicLorentzDrude1998=W_RakicLorentzDrude1998, - ), + variants={ + "Werner2009": W_Werner2009, + "RakicLorentzDrude1998": W_RakicLorentzDrude1998, + }, default="Werner2009", ), WS2=MaterialItem2D( name="Tungsten Disulfide", - variants=dict( - Li2014=WS2_Li2014, - ), + variants={ + "Li2014": WS2_Li2014, + }, default="Li2014", ), WSe2=MaterialItem2D( name="Tungsten Diselenide", - variants=dict( - Li2014=WSe2_Li2014, - ), + variants={ + "Li2014": WSe2_Li2014, + }, default="Li2014", ), Y2O3=MaterialItem( name="Yttrium Oxide", - variants=dict( - Horiba=Y2O3_Horiba, - Nigara1968=Y2O3_Nigara1968, - ), + variants={ + "Horiba": Y2O3_Horiba, + "Nigara1968": Y2O3_Nigara1968, + }, default="Horiba", ), YAG=MaterialItem( name="Yttrium Aluminium Garnet", - variants=dict( - Zelmon1998=YAG_Zelmon1998, - ), + variants={ + "Zelmon1998": YAG_Zelmon1998, + }, default="Zelmon1998", ), ZrO2=MaterialItem( name="Zirconium Oxide", - variants=dict( - Horiba=ZrO2_Horiba, - ), + variants={ + "Horiba": ZrO2_Horiba, + }, default="Horiba", ), aSi=MaterialItem( name="Silicon (Amorphous)", - variants=dict( - Horiba=aSi_Horiba, - ), + variants={ + "Horiba": aSi_Horiba, + }, default="Horiba", ), cSi=MaterialItem( name="Silicon (Crystalline)", - variants=dict( - Palik_Lossless=cSi_PalikLossless, - Palik_Lossy=cSi_PalikLossy, - SalzbergVilla1957=cSi_SalzbergVilla1957, - Li1993_293K=cSi_Li1993_293K, - Green2008=cSi_Green2008, - Green2008_Lossless=cSi_Green2008Lossless, - Si_MultiPhysics=cSi_MultiPhysics, - ), + variants={ + "Palik_Lossless": cSi_PalikLossless, + "Palik_Lossy": cSi_PalikLossy, + "SalzbergVilla1957": cSi_SalzbergVilla1957, + "Li1993_293K": cSi_Li1993_293K, + "Green2008": cSi_Green2008, + "Green2008_Lossless": cSi_Green2008Lossless, + "Si_MultiPhysics": cSi_MultiPhysics, + }, default="Green2008", ), LiNbO3=MaterialItemUniaxial( name="Lithium niobate", - variants=dict(Zelmon1997=LiNbO3_Zelmon1997), + variants={"Zelmon1997": LiNbO3_Zelmon1997}, default="Zelmon1997", ), graphene=Graphene, diff --git a/tidy3d/material_library/material_reference.py b/tidy3d/material_library/material_reference.py index ac27867dfe..53cfa89eca 100644 --- a/tidy3d/material_library/material_reference.py +++ b/tidy3d/material_library/material_reference.py @@ -1,8 +1,10 @@ """Holds the reference materials for Tidy3D material library.""" +from __future__ import annotations + import pydantic.v1 as pd -from ..components.base import Tidy3dBaseModel +from tidy3d.components.base import Tidy3dBaseModel class ReferenceData(Tidy3dBaseModel): @@ -31,188 +33,195 @@ class ReferenceData(Tidy3dBaseModel): ) -material_refs = dict( - Li2014=ReferenceData( +material_refs = { + "Li2014": ReferenceData( journal="Y. Li, A. Chernikov, X. Zhang, A. Rigosi, H. M. Hill, A. M. van der Zande, " "D. A. Chenet, E. Shih, J. Hone, and T. F. Heinz. Measurement of the optical dielectric " "function of monolayer transition-metal dichalcogenides: MoS2, MoSe2, WS2, and WSe2, " "Phys. Rev. B 90, 205422 (2014)", doi="https://doi.org/10.1103/PhysRevB.90.205422", ), - Yang2015=ReferenceData( + "Yang2015": ReferenceData( journal="H. U. Yang, J. D'Archangel, M. L. Sundheimer, E. Tucker, G. D. Boreman, " "M. B. Raschke. Optical dielectric function of silver, Phys. Rev. B 91, 235137 (2015)", doi="https://journals.aps.org/prb/abstract/10.1103/PhysRevB.91.235137", ), - Olmon2012=ReferenceData( + "Olmon2012": ReferenceData( journal="R. L. Olmon, B. Slovick, T. W. Johnson, D. Shelton, S.-H. Oh, " "G. D. Boreman, and M. B. Raschke. Optical dielectric function of " "gold, Phys. Rev. B 86, 235147 (2012)", doi="https://doi.org/10.1103/PhysRevB.86.235147", ), - Rakic1995=ReferenceData( + "Rakic1995": ReferenceData( journal="A. D. Rakic. Algorithm for the determination of intrinsic optical " "constants of metal films: application to aluminum, Appl. Opt. 34, 4755-4767 (1995)", doi="https://doi.org/10.1364/AO.34.004755", ), - Rakic1998=ReferenceData( + "Rakic1998": ReferenceData( journal="A. D. Rakic, A. B. Djurisic, J. M. Elazar, and M. L. Majewski. " "Optical properties of metallic films for vertical-cavity optoelectronic " "devices, Appl. Opt. 37, 5271-5283 (1998)", doi="https://doi.org/10.1364/AO.37.005271", ), - JohnsonChristy1972=ReferenceData( + "JohnsonChristy1972": ReferenceData( journal="P. B. Johnson and R. W. Christy. Optical constants of the noble " "metals, Phys. Rev. B 6, 4370-4379 (1972)", doi="https://doi.org/10.1103/PhysRevB.6.4370", ), - Horiba=ReferenceData( + "Horiba": ReferenceData( journal="Horiba Technical Note 08: Lorentz Dispersion Model", url="http://www.horiba.com/fileadmin/uploads/Scientific/Downloads" "/OpticalSchool_CN/TN/ellipsometer/Lorentz_Dispersion_Model.pdf", ), - FernOnton1971=ReferenceData( + "FernOnton1971": ReferenceData( journal="R. E. Fern and A. Onton. Refractive index of AlAs, " "J. Appl. Phys. 42, 3499-3500 (1971)", doi="https://doi.org/10.1063/1.1660760", ), - Sultanova2009=ReferenceData( + "Sultanova2009": ReferenceData( journal="N. Sultanova, S. Kasarova and I. Nikolov. Dispersion properties " "of optical polymers, Acta Physica Polonica A 116, 585-587 (2009)", doi="https://doi.org/10.12693/aphyspola.116.585", ), - Malitson1965=ReferenceData( + "Malitson1965": ReferenceData( journal="I. H. Malitson. Interspecimen comparison of the refractive " "index of fused silica, J. Opt. Soc. Am. 55, 1205-1208 (1965)", doi="https://doi.org/10.1364/JOSA.55.001205", ), - Tan1998=ReferenceData( + "Tan1998": ReferenceData( journal="C. Z. Tan. Determination of refractive index of silica glass " "for infrared wavelengths by IR spectroscopy, J. Non-Cryst. Solids 223, 158-163 (1998)", doi="https://doi.org/10.1016/S0022-3093(97)00438-9", ), - Skauli2003=ReferenceData( + "Skauli2003": ReferenceData( journal="T. Skauli, P. S. Kuo, K. L. Vodopyanov, T. J. Pinguet, " "O. Levi, L. A. Eyres, J. S. Harris, M. M. Fejer, B. Gerard, " "L. Becouarn, and E. Lallier. Improved dispersion relations " "for GaAs and applications to nonlinear optics, J. Appl. Phys., 94, 6447-6455 (2003)", doi="https://doi.org/10.1063/1.1621740", ), - Icenogle1976=ReferenceData( + "Icenogle1976": ReferenceData( journal="H. W. Icenogle, Ben C. Platt, and William L. Wolfe. " "Refractive indexes and temperature coefficients of germanium " "and silicon Appl. Opt. 15 2348-2351 (1976)", doi="https://doi.org/10.1364/AO.15.002348", ), - Barnes1979=ReferenceData( + "Barnes1979": ReferenceData( journal="N. P. Barnes and M. S. Piltch. Temperature-dependent " "Sellmeier coefficients and nonlinear optics average power limit " "for germanium J. Opt. Soc. Am. 69 178-180 (1979)", doi="https://doi.org/10.1364/JOSA.69.000178", ), - Pettit1965=ReferenceData( + "Nunley2016": ReferenceData( + journal="T. S. Nunley, N. S. Fernando, N. Samarasingha, J. M. Moya, " + "C. M. Nelson, A. A. Medina, and S. Zollner. Optical constants of " + "germanium and thermally grown germanium dioxide from 0.5 to 6.6eV " + "via a multisample ellipsometry investigation, J. Vac. Sci. Technol. B 34, 061205 (2016)", + doi="https://doi.org/10.1116/1.4963075", + ), + "Pettit1965": ReferenceData( journal="G. D. Pettit and W. J. Turner. Refractive index of InP, " "J. Appl. Phys. 36, 2081 (1965)", doi="https://doi.org/10.1063/1.1714410", ), - Pikhtin1978=ReferenceData( + "Pikhtin1978": ReferenceData( journal="A. N. Pikhtin and A. D. Yas'kov. Disperson of the " "refractive index of semiconductors with diamond and zinc-blende " "structures, Sov. Phys. Semicond. 12, 622-626 (1978)", ), - HandbookOptics=ReferenceData( + "HandbookOptics": ReferenceData( journal="Handbook of Optics, 2nd edition, Vol. 2. McGraw-Hill 1994 (ISBN 9780070479746)", ), - StephensMalitson1952=ReferenceData( + "StephensMalitson1952": ReferenceData( journal="R. E. Stephens and I. H. Malitson. Index of refraction of " "magnesium oxide, J. Res. Natl. Bur. Stand. 49 249-252 (1952)", doi="https://doi.org/10.6028/jres.049.025", ), - Werner2009=ReferenceData( + "Werner2009": ReferenceData( journal="W. S. M. Werner, K. Glantschnig, C. Ambrosch-Draxl. " "Optical constants and inelastic electron-scattering data for 17 " "elemental metals, J. Phys Chem Ref. Data 38, 1013-1092 (2009)", doi="https://doi.org/10.1063/1.3243762", ), - Luke2015=ReferenceData( + "Luke2015": ReferenceData( journal="K. Luke, Y. Okawachi, M. R. E. Lamont, A. L. Gaeta, M. Lipson. " "Broadband mid-infrared frequency comb generation in a Si3N4 microresonator, " "Opt. Lett. 40, 4823-4826 (2015)", doi="https://doi.org/10.1364/OL.40.004823", ), - Philipp1973=ReferenceData( + "Philipp1973": ReferenceData( journal="H. R. Philipp. Optical properties of silicon nitride, " "J. Electrochim. Soc. 120, 295-300 (1973)", doi="https://doi.org/10.1149/1.2403440", ), - Baak1982=ReferenceData( + "Baak1982": ReferenceData( journal="T. Baak. Silicon oxynitride; a material for GRIN optics, " "Appl. Optics 21, 1069-1072 (1982)", doi="https://doi.org/10.1364/AO.21.001069", ), - Nigara1968=ReferenceData( + "Nigara1968": ReferenceData( journal="Y. Nigara. Measurement of the optical constants of yttrium oxide, " "Jpn. J. Appl. Phys. 7, 404-408 (1968)", doi="https://doi.org/10.1143/JJAP.7.404", ), - Zelmon1997=ReferenceData( + "Zelmon1997": ReferenceData( journal="D. E. Zelmon, D. L. Small and D. Jundt. Infrared corrected Sellmeier " "coefficients for congruently grown lithium niobate and 5 mol.% magnesium oxide-doped " "lithium niobate, J. Opt. Soc. Am. B 14, 3319-3322 (1997)", doi="https://doi.org/10.1364/JOSAB.14.003319", ), - Zelmon1998=ReferenceData( + "Zelmon1998": ReferenceData( journal="D. E. Zelmon, D. L. Small and R. Page. Refractive-index measurements " "of undoped yttrium aluminum garnet from 0.4 to 5.0 μm, Appl. Opt. 37, 4933-4935 (1998)", doi="https://doi.org/10.1364/AO.37.004933", ), - SalzbergVilla1957=ReferenceData( + "SalzbergVilla1957": ReferenceData( journal="C. D. Salzberg and J. J. Villa. Infrared Refractive Indexes of " "Silicon, Germanium and Modified Selenium Glass, J. Opt. Soc. Am., 47, 244-246 (1957)", doi="https://doi.org/10.1364/JOSA.47.000244", ), - Tatian1984=ReferenceData( + "Tatian1984": ReferenceData( journal="B. Tatian. Fitting refractive-index data with the Sellmeier " "dispersion formula, Appl. Opt. 23, 4477-4485 (1984)", doi="https://doi.org/10.1364/AO.23.004477", ), - Li1993_293K=ReferenceData( + "Li1993_293K": ReferenceData( journal="H. H. Li. Refractive index of silicon and germanium and its wavelength " "and temperature derivatives, J. Phys. Chem. Ref. Data 9, 561-658 (1993)", doi="https://doi.org/10.1063/1.555624", ), - Green2008=ReferenceData( + "Green2008": ReferenceData( journal="M. A. Green. Self-consistent optical parameters of intrinsic silicon " "at 300K including temperature coefficients, Sol. Energ. Mat. " "Sol. Cells 92, 1305–1310 (2008)", doi="https://doi.org/10.1016/j.solmat.2008.06.009", ), - Zemax=ReferenceData( + "Zemax": ReferenceData( journal="SCHOTT Zemax catalog 2017-01-20b", url="https://refractiveindex.info/download/data/2017/schott_2017-01-20.pdf", ), - Hanson2008=ReferenceData( + "Hanson2008": ReferenceData( journal="George W. Hanson. Dyadic Green's Functions for an Anisotropic, " "Non-Local Model of Biased Graphene, IEEE Trans. Antennas Propag. 56, 3, 747-757 (2008)", doi="https://doi.org/10.1109/TAP.2008.917005", ), - Burnett2016=ReferenceData( + "Burnett2016": ReferenceData( journal="John H. Burnett, Simon G. Kaplan, Eric Stover, and Adam Phenis, " "Refractive index measurements of Ge, " "Proc. SPIE 9974, Infrared Sensors, Devices, and Applications VI, 99740X " "(20 September 2016)", doi="https://doi.org/10.1117/12.2237978", ), - Palik=ReferenceData( - journal="E. D. Palik. Handbook of Optical Constants of Solids, " "Academic Press (1998)", + "Palik": ReferenceData( + journal="E. D. Palik. Handbook of Optical Constants of Solids, Academic Press (1998)", doi="https://doi.org/10.1016/B978-0-08-055630-7.50001-8", ), - Palik_Lossy=ReferenceData( - journal="E. D. Palik. Handbook of Optical Constants of Solids, " "Academic Press (1998)", + "Palik_Lossy": ReferenceData( + journal="E. D. Palik. Handbook of Optical Constants of Solids, Academic Press (1998)", doi="https://doi.org/10.1016/B978-0-08-055630-7.50001-8", ), - Palik_Lossless=ReferenceData( - journal="E. D. Palik. Handbook of Optical Constants of Solids, " "Academic Press (1998)", + "Palik_Lossless": ReferenceData( + journal="E. D. Palik. Handbook of Optical Constants of Solids, Academic Press (1998)", doi="https://doi.org/10.1016/B978-0-08-055630-7.50001-8", ), -) +} diff --git a/tidy3d/material_library/parametric_materials.py b/tidy3d/material_library/parametric_materials.py index 02608aca9d..3f055091a7 100644 --- a/tidy3d/material_library/parametric_materials.py +++ b/tidy3d/material_library/parametric_materials.py @@ -1,23 +1,17 @@ """Parametric material models.""" +from __future__ import annotations + import warnings from abc import ABC, abstractmethod -from typing import List, Tuple import numpy as np import pydantic.v1 as pd -from ..components.base import Tidy3dBaseModel -from ..components.medium import Drude, Medium2D, PoleResidue -from ..constants import ELECTRON_VOLT, EPSILON_0, HBAR, K_B, KELVIN, Q_e -from ..log import log - -try: - from scipy import integrate - - INTEGRATE_AVAILABLE = True -except ImportError: - INTEGRATE_AVAILABLE = False +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.medium import Drude, Medium2D, PoleResidue +from tidy3d.constants import ELECTRON_VOLT, EPSILON_0, HBAR, K_B, KELVIN, Q_e +from tidy3d.log import log # default values of the physical parameters for graphene # scattering rate in eV @@ -102,7 +96,7 @@ class Graphene(ParametricVariantItem2D): "Otherwise, the intraband terms only give a simpler Drude-type model relevant " "only at low frequency (THz).", ) - interband_fit_freq_nodes: List[Tuple[float, float]] = pd.Field( + interband_fit_freq_nodes: list[tuple[float, float]] = pd.Field( None, title="Interband fitting frequency nodes", description="Frequency nodes for fitting interband term. " @@ -199,7 +193,7 @@ def interband_pole_residue(self) -> PoleResidue: ) return pole_residue_filtered - def numerical_conductivity(self, freqs: List[float]) -> List[complex]: + def numerical_conductivity(self, freqs: list[float]) -> list[complex]: """Numerically calculate the conductivity. If this differs from the conductivity of the :class:`.Medium2D`, it is due to error while fitting the interband term, and you may try values of ``interband_fit_freq_nodes`` @@ -219,7 +213,7 @@ def numerical_conductivity(self, freqs: List[float]) -> List[complex]: inter_sigma = self.interband_conductivity(freqs) return intra_sigma + inter_sigma - def interband_conductivity(self, freqs: List[float]) -> List[complex]: + def interband_conductivity(self, freqs: list[float]) -> list[complex]: """Numerically integrate interband term. Parameters @@ -232,6 +226,12 @@ def interband_conductivity(self, freqs: List[float]) -> List[complex]: List[complex] The list of corresponding interband conductivities, in S. """ + try: + from scipy import integrate + + INTEGRATE_AVAILABLE = True + except ImportError: + INTEGRATE_AVAILABLE = False def fermi(E: float) -> float: """Fermi distribution.""" @@ -271,9 +271,9 @@ def integrand(E: float, omega: float) -> float: def _fit_interband_conductivity( self, - freqs: List[float], - sigma: List[complex], - indslist: List[Tuple[int, int]], + freqs: list[float], + sigma: list[complex], + indslist: list[tuple[int, int]], ): """Fit the interband conductivity with a Pade approximation, as described in @@ -296,7 +296,7 @@ def _fit_interband_conductivity( A pole-residue model approximating the interband conductivity. """ - def evaluate_coeffslist(omega: List[float], coeffslist: List[List[float]]) -> List[float]: + def evaluate_coeffslist(omega: list[float], coeffslist: list[list[float]]) -> list[float]: """Evaluate the Pade approximants given by ``coeffslist` to ``omega``. Each item in ``coeffslist`` is a list of four coefficients corresponding to a single Pade term.""" @@ -308,8 +308,8 @@ def evaluate_coeffslist(omega: List[float], coeffslist: List[List[float]]) -> Li return res def fit_single( - omega: List[float], sigma: List[complex], inds: Tuple[int, int] - ) -> List[float]: + omega: list[float], sigma: list[complex], inds: tuple[int, int] + ) -> list[float]: """Fit a single Pade approximant of degree (1, 2) to ``sigma`` as a real function of i ``omega``. The method is described in @@ -331,11 +331,11 @@ def fit_single( return np.linalg.pinv(matrix) @ np.array([gamma[0], eta[0], gamma[1], eta[1]]) def optimize( - omega: List[float], - sigma: List[complex], - indslist: List[Tuple[int, int]], - coeffslist: List[List[float]], - ) -> List[float]: + omega: list[float], + sigma: list[complex], + indslist: list[tuple[int, int]], + coeffslist: list[list[float]], + ) -> list[float]: """Optimize the coefficients in ``coeffslist`` by sampling ``omega`` and ``sigma`` at the indices in ``indslist``.""" for _ in range(self.interband_fit_num_iters): @@ -346,7 +346,7 @@ def optimize( coeffslist[j] = fit_single(omega, curr_res, indslist[j]) return coeffslist - def get_pole_residue(coeffslist: List[List[float]]) -> PoleResidue: + def get_pole_residue(coeffslist: list[list[float]]) -> PoleResidue: """Convert a list of Pade coefficients into a :class:`.PoleResidue` model.""" poles = [] for alpha0, alpha1, beta1, beta2 in coeffslist: @@ -398,6 +398,6 @@ def _filter_poles(self, medium: PoleResidue) -> PoleResidue: else: poles += [(a, c)] return PoleResidue( - poles=poles + [(0, zero_res)], + poles=[*poles, (0, zero_res)], frequency_range=(0, GRAPHENE_FIT_FREQ_MAX), ) diff --git a/tidy3d/material_library/util.py b/tidy3d/material_library/util.py index 4162a0e33f..206cbdf4a7 100644 --- a/tidy3d/material_library/util.py +++ b/tidy3d/material_library/util.py @@ -1,5 +1,6 @@ +from __future__ import annotations + from io import StringIO -from typing import List from rich.console import Console from rich.panel import Panel @@ -7,7 +8,7 @@ from rich.text import Text from rich.tree import Tree -from ..components.viz import FLEXCOMPUTE_COLORS +from tidy3d.components.viz import FLEXCOMPUTE_COLORS MAX_POLES_TO_DISPLAY = 3 @@ -55,7 +56,7 @@ def variant_name(v): return name -def summarize_medium(med) -> List[str]: +def summarize_medium(med) -> list[str]: """Returns relevant medium information for display.""" lines = [] @@ -108,11 +109,6 @@ def summarize_variant_item(v) -> str: return "\n".join(lines) -def get_hex_formatted_string(color_key): - """Return a hex formatted string from the FLEXCOMPUTE_COLORS that can be used with rich printing.""" - return f"#{FLEXCOMPUTE_COLORS[color_key]:06x}" - - def repr_pretty_with_rich(obj, p, cycle): """Enable _repr_pretty_ for jupyter notebooks to use the rich printing output.""" if cycle: @@ -147,28 +143,24 @@ def summarize_material_library_rich(matlib): """Returns a Rich Table summarizing the MaterialLibrary.""" table = Table( - title=f"[bold {get_hex_formatted_string('brand_black')}]Material Library Summary[/]", + title=f"[bold {FLEXCOMPUTE_COLORS['brand_black']}]Material Library Summary[/]", show_header=True, - header_style=f"bold {get_hex_formatted_string('brand_black')}", - border_style=f"{get_hex_formatted_string('brand_black')}", + header_style=f"bold {FLEXCOMPUTE_COLORS['brand_black']}", + border_style=f"{FLEXCOMPUTE_COLORS['brand_black']}", expand=False, # Don't force table to full terminal width ) + table.add_column("Key", style=f"{FLEXCOMPUTE_COLORS['brand_blue']}", width=18, justify="center") table.add_column( - "Key", style=f"{get_hex_formatted_string('brand_blue')}", width=18, justify="center" - ) - table.add_column( - "Name", style=f"{get_hex_formatted_string('brand_purple')}", min_width=20, justify="center" + "Name", style=f"{FLEXCOMPUTE_COLORS['brand_purple']}", min_width=20, justify="center" ) table.add_column( "Default Variant", - style=f"{get_hex_formatted_string('brand_green')}", + style=f"{FLEXCOMPUTE_COLORS['brand_green']}", min_width=20, justify="center", ) - table.add_column( - "# Variants", style=f"{get_hex_formatted_string('brand_green')}", justify="center" - ) + table.add_column("# Variants", style=f"{FLEXCOMPUTE_COLORS['brand_green']}", justify="center") # Iterate through the sorted items for consistent order for key, mat_item in sorted(matlib.items()): @@ -197,7 +189,7 @@ def summarize_material_library_rich(matlib): def summarize_material_item_rich(m): """Returns a Rich Tree representation summarizing the MaterialItem.""" - tree_title = f"[bold {get_hex_formatted_string('brand_purple')}]Material Summary: {m.name}[/]" + tree_title = f"[bold {FLEXCOMPUTE_COLORS['brand_purple']}]Material Summary: {m.name}[/]" tree = Tree(tree_title) # Add a subtree for the variants @@ -212,7 +204,7 @@ def summarize_material_item_rich(m): # Indicate if there are no variants variants_node.add("[italic]None[/italic]") - return Panel(tree, border_style=f"{get_hex_formatted_string('brand_purple')}", expand=False) + return Panel(tree, border_style=f"{FLEXCOMPUTE_COLORS['brand_purple']}", expand=False) def summarize_variant_item_rich(v): @@ -220,9 +212,7 @@ def summarize_variant_item_rich(v): name = variant_name(v) - tree_title = Text( - f"Variant Summary: {name}", style=f"bold {get_hex_formatted_string('brand_green')}" - ) + tree_title = Text(f"Variant Summary: {name}", style=f"bold {FLEXCOMPUTE_COLORS['brand_green']}") tree = Tree(tree_title) ref_node = tree.add("[bold]References[/bold]") @@ -252,10 +242,10 @@ def summarize_variant_item_rich(v): if mediums: for med_key, med in mediums.items(): medium_type_node = mediums_node.add( - f"[italic {get_hex_formatted_string('brand_blue')}]{med_key}[/]" + f"[italic {FLEXCOMPUTE_COLORS['brand_blue']}]{med_key}[/]" ) add_medium_details_to_tree(med, medium_type_node) else: mediums_node.add("[italic]None[/italic]") - return Panel(tree, border_style=f"{get_hex_formatted_string('brand_green')}", expand=False) + return Panel(tree, border_style=f"{FLEXCOMPUTE_COLORS['brand_green']}", expand=False) diff --git a/tidy3d/packaging.py b/tidy3d/packaging.py index 43aeb8d4d5..a5a8d9d368 100644 --- a/tidy3d/packaging.py +++ b/tidy3d/packaging.py @@ -4,12 +4,15 @@ This section should only depend on the standard core installation in the pyproject.toml, and should not depend on any other part of the codebase optional imports. """ +from __future__ import annotations + import functools from importlib import import_module from typing import Literal import numpy as np +from .config import config from .exceptions import Tidy3dImportError vtk = { @@ -20,6 +23,8 @@ "numpy_to_vtk": None, } +tidy3d_extras = {"mod": None, "use_local_subpixel": False} + def check_import(module_name: str) -> bool: """ @@ -89,7 +94,7 @@ def checks_modules_import(*args, **kwargs): f"Please install the '{module}' dependencies using, for example, " f"'pip install tidy3d[]" ) - elif required == "any": + if required == "any": # Means we need to verify that at least one of the modules is available if ( not any(available_modules_status) @@ -140,12 +145,12 @@ def _fn(*args, **kwargs): if vtk["mod"].vtkIdTypeArray().GetDataTypeSize() == 4: vtk["id_type"] = np.int32 - except ImportError: + except ImportError as exc: raise Tidy3dImportError( "The package 'vtk' is required for this operation, but it was not found. " "Please install the 'vtk' dependencies using, for example, " "'pip install .[vtk]'." - ) + ) from exc return fn(*args, **kwargs) @@ -173,3 +178,39 @@ def get_numpy_major_version(module=np): major_version = int(module_version.split(".")[0]) return major_version + + +def supports_local_subpixel(fn): + """When decorating a method, checks that 'tidy3d-extras' is available, + conditioned on 'config.use_local_subpixel'.""" + + @functools.wraps(fn) + def _fn(*args, **kwargs): + if config.use_local_subpixel is False: + tidy3d_extras["use_local_subpixel"] = False + tidy3d_extras["mod"] = None + else: + # first try to import the module + if tidy3d_extras["mod"] is None: + try: + import tidy3d_extras as tidy3d_extras_mod + + _ = tidy3d_extras_mod.__version__ + + tidy3d_extras["mod"] = tidy3d_extras_mod + tidy3d_extras["use_local_subpixel"] = True + except (ImportError, AttributeError) as exc: + tidy3d_extras["mod"] = None + tidy3d_extras["use_local_subpixel"] = False + if config.use_local_subpixel is True: + raise Tidy3dImportError( + "The package 'tidy3d-extras' is required for this " + "operation when 'config.use_local_subpixel' is 'True'. " + "Please install the 'tidy3d-extras' package using, for " + "example, 'pip install tidy3d-extras'. NOTE: This " + "feature is not yet supported." + ) from exc + + return fn(*args, **kwargs) + + return _fn diff --git a/tidy3d/plugins/adjoint/__init__.py b/tidy3d/plugins/adjoint/__init__.py index 6cf3f04f84..03919617aa 100644 --- a/tidy3d/plugins/adjoint/__init__.py +++ b/tidy3d/plugins/adjoint/__init__.py @@ -1,6 +1,31 @@ """Imports for adjoint plugin.""" +# ruff: noqa: E402 # import the jax version of tidy3d components +from __future__ import annotations + +from textwrap import dedent + +from tidy3d.log import log + +_DOC_URL = "https://github.com/flexcompute/tidy3d/blob/develop/tidy3d/plugins/autograd/README.md" + +_MSG = dedent( + f""" + The 'adjoint' plugin (legacy JAX-based adjoint plugin) was deprecated in Tidy3D '2.7.0' and will be disabled as of '2.9.0'. + + Migrate to the native autograd workflow: + import tidy3d as td + import autograd.numpy as np + from autograd import grad + + It uses standard 'td.' objects, has fewer dependencies, and offers a smoother optimization experience. + Full guide: {_DOC_URL} + """ +).strip() + +log.warning(_MSG) + try: import jax @@ -27,21 +52,21 @@ from .web import run, run_async __all__ = [ + "JaxAnisotropicMedium", "JaxBox", - "JaxPolySlab", "JaxComplexPolySlab", + "JaxCustomMedium", + "JaxDataArray", "JaxGeometryGroup", "JaxMedium", - "JaxAnisotropicMedium", - "JaxCustomMedium", - "JaxStructure", - "JaxStructureStaticMedium", - "JaxStructureStaticGeometry", - "JaxSimulation", - "JaxSimulationData", "JaxModeData", "JaxPermittivityDataset", - "JaxDataArray", + "JaxPolySlab", + "JaxSimulation", + "JaxSimulationData", + "JaxStructure", + "JaxStructureStaticGeometry", + "JaxStructureStaticMedium", "run", "run_async", ] diff --git a/tidy3d/plugins/adjoint/components/__init__.py b/tidy3d/plugins/adjoint/components/__init__.py index c9d9cdb5cc..bbd71e0a7d 100644 --- a/tidy3d/plugins/adjoint/components/__init__.py +++ b/tidy3d/plugins/adjoint/components/__init__.py @@ -1,6 +1,8 @@ """Component imports for adjoint plugin. from tidy3d.plugins.adjoint.components import *""" # import the jax version of tidy3d components +from __future__ import annotations + from .data.data_array import JaxDataArray from .data.dataset import JaxPermittivityDataset from .data.monitor_data import JaxModeData @@ -11,19 +13,19 @@ from .structure import JaxStructure, JaxStructureStaticGeometry, JaxStructureStaticMedium __all__ = [ + "JaxAnisotropicMedium", "JaxBox", - "JaxPolySlab", "JaxComplexPolySlab", + "JaxCustomMedium", + "JaxDataArray", "JaxGeometryGroup", "JaxMedium", - "JaxAnisotropicMedium", - "JaxCustomMedium", - "JaxStructure", - "JaxStructureStaticMedium", - "JaxStructureStaticGeometry", - "JaxSimulation", - "JaxSimulationData", "JaxModeData", "JaxPermittivityDataset", - "JaxDataArray", + "JaxPolySlab", + "JaxSimulation", + "JaxSimulationData", + "JaxStructure", + "JaxStructureStaticGeometry", + "JaxStructureStaticMedium", ] diff --git a/tidy3d/plugins/adjoint/components/base.py b/tidy3d/plugins/adjoint/components/base.py index 1fcd6baaa7..943295ef98 100644 --- a/tidy3d/plugins/adjoint/components/base.py +++ b/tidy3d/plugins/adjoint/components/base.py @@ -3,7 +3,7 @@ from __future__ import annotations import json -from typing import Any, Callable, List, Tuple +from typing import Any, Callable, Optional import jax import numpy as np @@ -11,7 +11,8 @@ from jax.tree_util import tree_flatten as jax_tree_flatten from jax.tree_util import tree_unflatten as jax_tree_unflatten -from ....components.base import Tidy3dBaseModel +from tidy3d.components.base import Tidy3dBaseModel + from .data.data_array import JAX_DATA_ARRAY_TAG, JaxDataArray # end of the error message when a ``_validate_web_adjoint`` exception is raised @@ -36,7 +37,7 @@ class JaxObject(Tidy3dBaseModel): """Shortcut to get names of fields with certain properties.""" @classmethod - def _get_field_names(cls, field_key: str) -> List[str]: + def _get_field_names(cls, field_key: str) -> list[str]: """Get all fields where ``field_key`` defined in the ``pydantic.Field``.""" fields = [] for field_name, model_field in cls.__fields__.items(): @@ -46,17 +47,17 @@ def _get_field_names(cls, field_key: str) -> List[str]: return fields @classmethod - def get_jax_field_names(cls) -> List[str]: + def get_jax_field_names(cls) -> list[str]: """Returns list of field names where ``jax_field=True``.""" return cls._get_field_names("jax_field") @classmethod - def get_jax_leaf_names(cls) -> List[str]: + def get_jax_leaf_names(cls) -> list[str]: """Returns list of field names where ``stores_jax_for`` defined.""" return cls._get_field_names("stores_jax_for") @classmethod - def get_jax_field_names_all(cls) -> List[str]: + def get_jax_field_names_all(cls) -> list[str]: """Returns list of field names where ``jax_field=True`` or ``stores_jax_for`` defined.""" jax_field_names = cls.get_jax_field_names() jax_leaf_names = cls.get_jax_leaf_names() @@ -72,11 +73,10 @@ def jax_fields(self) -> dict: def _validate_web_adjoint(self) -> None: """Run validators for this component, only if using ``tda.web.run()``.""" - pass """Methods needed for jax to register arbitrary classes.""" - def tree_flatten(self) -> Tuple[list, dict]: + def tree_flatten(self) -> tuple[list, dict]: """How to flatten a :class:`.JaxObject` instance into a ``pytree``.""" children = [] aux_data = self.dict() @@ -95,8 +95,7 @@ def fix_numpy(value: Any) -> Any: return value.tolist() if isinstance(value, dict): return {key: fix_numpy(val) for key, val in value.items()} - else: - return value + return value aux_data = fix_numpy(aux_data) @@ -153,7 +152,7 @@ def from_tidy3d(cls, tidy3d_obj: Tidy3dBaseModel) -> JaxObject: @property def exclude_fields_leafs_only(self) -> set: """Fields to exclude from ``self.dict()``, ``"type"`` and all ``jax`` leafs.""" - return set(["type"] + self.get_jax_leaf_names()) + return {"type", *self.get_jax_leaf_names()} """Accounting with jax and regular fields.""" @@ -208,7 +207,7 @@ def strip_data_array(val: Any) -> Any: return JAX_DATA_ARRAY_TAG return {k: strip_data_array(v) for k, v in val.items()} - elif isinstance(val, (tuple, list)): + if isinstance(val, (tuple, list)): return [strip_data_array(v) for v in val] return val @@ -218,7 +217,7 @@ def strip_data_array(val: Any) -> Any: # TODO: replace with implementing these in DataArray - def to_hdf5(self, fname: str, custom_encoders: List[Callable] = None) -> None: + def to_hdf5(self, fname: str, custom_encoders: Optional[list[Callable]] = None) -> None: """Exports :class:`JaxObject` instance to .hdf5 file. Parameters @@ -249,7 +248,7 @@ def data_array_encoder(fname: str, group_path: str, value: Any) -> None: @classmethod def dict_from_hdf5( - cls, fname: str, group_path: str = "", custom_decoders: List[Callable] = None + cls, fname: str, group_path: str = "", custom_decoders: Optional[list[Callable]] = None ) -> dict: """Loads a dictionary containing the model contents from a .hdf5 file. diff --git a/tidy3d/plugins/adjoint/components/data/data_array.py b/tidy3d/plugins/adjoint/components/data/data_array.py index 083dd9d2e9..0fdcc61284 100644 --- a/tidy3d/plugins/adjoint/components/data/data_array.py +++ b/tidy3d/plugins/adjoint/components/data/data_array.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Any, Dict, List, Literal, Sequence, Tuple, Union +from collections.abc import Sequence +from typing import Any, Literal, Optional, Union import h5py import jax @@ -12,8 +13,8 @@ import xarray as xr from jax.tree_util import register_pytree_node_class -from .....components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from .....exceptions import AdjointError, DataError, Tidy3dKeyError +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.exceptions import AdjointError, DataError, Tidy3dKeyError # condition setting when to set value in DataArray to zero: # if abs(val) <= VALUE_FILTER_THRESHOLD * max(abs(val)) @@ -34,7 +35,7 @@ class JaxDataArray(Tidy3dBaseModel): jax_field=True, ) - coords: Dict[str, list] = pd.Field( + coords: dict[str, list] = pd.Field( ..., title="Coords", description="Dictionary storing the coordinates, namely ``(direction, f, mode_index)``.", @@ -152,18 +153,18 @@ def as_list(self) -> list: def real(self) -> np.ndarray: """Real part of self.""" new_values = jnp.real(self.as_jnp_array) - return self.copy(update=dict(values=new_values)) + return self.copy(update={"values": new_values}) @cached_property def imag(self) -> np.ndarray: """Imaginary part of self.""" new_values = jnp.imag(self.as_jnp_array) - return self.copy(update=dict(values=new_values)) + return self.copy(update={"values": new_values}) def conj(self) -> JaxDataArray: """Complex conjugate of self.""" new_values = jnp.conj(self.as_jnp_array) - return self.copy(update=dict(values=new_values)) + return self.copy(update={"values": new_values}) def __abs__(self) -> JaxDataArray: """Absolute value of self's values.""" @@ -219,7 +220,7 @@ def __rmul__(self, other) -> JaxDataArray: """Multiply self with something else.""" return self * other - def sum(self, dim: str = None): + def sum(self, dim: Optional[str] = None): """Sum (optionally along a single or multiple dimensions).""" if dim is None: @@ -239,7 +240,7 @@ def sum(self, dim: str = None): ret = ret.sum(dim=dim_i) return ret - def squeeze(self, dim: str = None, drop: bool = True) -> JaxDataArray: + def squeeze(self, dim: Optional[str] = None, drop: bool = True) -> JaxDataArray: """Remove any non-zero dims.""" if dim is None: @@ -294,7 +295,7 @@ def isel_single(self, coord_name: str, coord_index: int) -> JaxDataArray: return new_values # otherwise, return another JaxDataArray with the values and coords selected out - return self.copy(update=dict(values=new_values, coords=new_coords)) + return self.copy(update={"values": new_values, "coords": new_coords}) def isel(self, **isel_kwargs) -> JaxDataArray: """Select a value from the :class:`.JaxDataArray` by indexing into coordinates by index.""" @@ -313,7 +314,7 @@ def isel(self, **isel_kwargs) -> JaxDataArray: return self_sel def sel( - self, indexers: dict = None, method: Literal[None, "nearest"] = None, **sel_kwargs + self, indexers: Optional[dict] = None, method: Literal[None, "nearest"] = None, **sel_kwargs ) -> JaxDataArray: """Select a value from the :class:`.JaxDataArray` by indexing into coordinates by value. @@ -392,7 +393,7 @@ def _indices_literal(self, coord_list: list, values: Union[Any, Sequence[Any]]) return indices - def assign_coords(self, coords: dict = None, **coords_kwargs) -> JaxDataArray: + def assign_coords(self, coords: Optional[dict] = None, **coords_kwargs) -> JaxDataArray: """Assign new coordinates to this object.""" update_kwargs = self.coords.copy() @@ -407,7 +408,7 @@ def assign_coords(self, coords: dict = None, **coords_kwargs) -> JaxDataArray: update_kwargs = {key: np.array(value).tolist() for key, value in update_kwargs.items()} return self.updated_copy(coords=update_kwargs) - def multiply_at(self, value: complex, coord_name: str, indices: List[int]) -> JaxDataArray: + def multiply_at(self, value: complex, coord_name: str, indices: list[int]) -> JaxDataArray: """Multiply self by value at indices into .""" axis = list(self.coords.keys()).index(coord_name) scalar_data_arr = self.as_jnp_array @@ -498,7 +499,7 @@ def interp(self, kwargs=None, assume_sorted=None, **interp_kwargs) -> JaxDataArr return ret_value @cached_property - def nonzero_val_coords(self) -> Tuple[List[complex], Dict[str, Any]]: + def nonzero_val_coords(self) -> tuple[list[complex], dict[str, Any]]: """The value and coordinate associated with the only non-zero element of ``self.values``.""" values = np.nan_to_num(self.as_ndarray) @@ -519,7 +520,7 @@ def nonzero_val_coords(self) -> Tuple[List[complex], Dict[str, Any]]: return nonzero_values, nonzero_coords - def tree_flatten(self) -> Tuple[list, dict]: + def tree_flatten(self) -> tuple[list, dict]: """Jax works on the values, stash the coords for reconstruction.""" return self.values, self.coords diff --git a/tidy3d/plugins/adjoint/components/data/dataset.py b/tidy3d/plugins/adjoint/components/data/dataset.py index 6e4006816b..f8e357bbcb 100644 --- a/tidy3d/plugins/adjoint/components/data/dataset.py +++ b/tidy3d/plugins/adjoint/components/data/dataset.py @@ -1,10 +1,13 @@ """Defines jax-compatible datasets.""" +from __future__ import annotations + import pydantic.v1 as pd from jax.tree_util import register_pytree_node_class -from .....components.data.dataset import PermittivityDataset -from ..base import JaxObject +from tidy3d.components.data.dataset import PermittivityDataset +from tidy3d.plugins.adjoint.components.base import JaxObject + from .data_array import JaxDataArray diff --git a/tidy3d/plugins/adjoint/components/data/monitor_data.py b/tidy3d/plugins/adjoint/components/data/monitor_data.py index 23ed786958..62ccbbf639 100644 --- a/tidy3d/plugins/adjoint/components/data/monitor_data.py +++ b/tidy3d/plugins/adjoint/components/data/monitor_data.py @@ -3,36 +3,37 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, Dict, List, Union +from typing import Any, Union import jax.numpy as jnp import numpy as np import pydantic.v1 as pd from jax.tree_util import register_pytree_node_class -from .....components.base import cached_property -from .....components.data.data_array import ( +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import ( FreqModeDataArray, MixedModeDataArray, ModeAmpsDataArray, ScalarFieldDataArray, ) -from .....components.data.dataset import FieldDataset -from .....components.data.monitor_data import ( +from tidy3d.components.data.dataset import FieldDataset +from tidy3d.components.data.monitor_data import ( DiffractionData, FieldData, ModeData, ModeSolverData, MonitorData, ) -from .....components.geometry.base import Box -from .....components.source.base import Source -from .....components.source.current import CustomCurrentSource, PointDipole -from .....components.source.field import CustomFieldSource, ModeSource, PlaneWave -from .....components.source.time import GaussianPulse -from .....constants import C_0, ETA_0, MU_0 -from .....exceptions import AdjointError -from ..base import JaxObject +from tidy3d.components.geometry.base import Box +from tidy3d.components.source.base import Source +from tidy3d.components.source.current import CustomCurrentSource, PointDipole +from tidy3d.components.source.field import CustomFieldSource, ModeSource, PlaneWave +from tidy3d.components.source.time import GaussianPulse +from tidy3d.constants import C_0, ETA_0, MU_0 +from tidy3d.exceptions import AdjointError +from tidy3d.plugins.adjoint.components.base import JaxObject + from .data_array import JaxDataArray @@ -54,7 +55,7 @@ def from_monitor_data(cls, mnt_data: MonitorData) -> JaxMonitorData: return cls.parse_obj(self_dict) @abstractmethod - def to_adjoint_sources(self, fwidth: float) -> List[Source]: + def to_adjoint_sources(self, fwidth: float) -> list[Source]: """Construct a list of adjoint sources from this :class:`.JaxMonitorData`.""" @staticmethod @@ -87,7 +88,7 @@ class JaxModeData(JaxMonitorData, ModeData): jax_field=True, ) - def to_adjoint_sources(self, fwidth: float) -> List[ModeSource]: + def to_adjoint_sources(self, fwidth: float) -> list[ModeSource]: """Converts a :class:`.ModeData` to a list of adjoint :class:`.ModeSource`.""" amps, sel_coords = self.amps.nonzero_val_coords @@ -167,7 +168,7 @@ def __contains__(self, item: str) -> bool: def __getitem__(self, item: str) -> bool: return self.field_components[item] - def package_colocate_results(self, centered_fields: Dict[str, ScalarFieldDataArray]) -> Any: + def package_colocate_results(self, centered_fields: dict[str, ScalarFieldDataArray]) -> Any: """How to package the dictionary of fields computed via self.colocate().""" return self.updated_copy(**centered_fields) @@ -243,7 +244,7 @@ def time_reversed_copy(self) -> FieldData: "'time_reversed_copy' is not yet supported in the adjoint plugin." ) - def to_adjoint_sources(self, fwidth: float) -> List[CustomFieldSource]: + def to_adjoint_sources(self, fwidth: float) -> list[CustomFieldSource]: """Converts a :class:`.JaxFieldData` to a list of adjoint :class:`.CustomFieldSource.""" interpolate_source = True @@ -408,7 +409,7 @@ def power(self) -> JaxDataArray: return JaxDataArray(values=power_values, coords=power_coords) - def to_adjoint_sources(self, fwidth: float) -> List[PlaneWave]: + def to_adjoint_sources(self, fwidth: float) -> list[PlaneWave]: """Converts a :class:`.DiffractionData` to a list of adjoint :class:`.PlaneWave`.""" # extract the values coordinates of the non-zero amplitudes @@ -428,7 +429,11 @@ def to_adjoint_sources(self, fwidth: float) -> List[PlaneWave]: continue # select the propagation angles from the data - angle_sel_kwargs = dict(orders_x=int(order_x), orders_y=int(order_y), f=float(freq)) + angle_sel_kwargs = { + "orders_x": int(order_x), + "orders_y": int(order_y), + "f": float(freq), + } angle_theta = float(theta_data.sel(**angle_sel_kwargs)) angle_phi = float(phi_data.sel(**angle_sel_kwargs)) diff --git a/tidy3d/plugins/adjoint/components/data/sim_data.py b/tidy3d/plugins/adjoint/components/data/sim_data.py index 7568c9135e..d9f9cff5b0 100644 --- a/tidy3d/plugins/adjoint/components/data/sim_data.py +++ b/tidy3d/plugins/adjoint/components/data/sim_data.py @@ -2,20 +2,21 @@ from __future__ import annotations -from typing import Dict, List, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd import xarray as xr from jax.tree_util import register_pytree_node_class -from .....components.data.monitor_data import FieldData, MonitorDataType, PermittivityData -from .....components.data.sim_data import SimulationData -from .....components.source.current import PointDipole -from .....components.source.time import GaussianPulse -from .....log import log -from ..base import JaxObject -from ..simulation import JaxInfo, JaxSimulation +from tidy3d.components.data.monitor_data import FieldData, MonitorDataType, PermittivityData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.source.current import PointDipole +from tidy3d.components.source.time import GaussianPulse +from tidy3d.log import log +from tidy3d.plugins.adjoint.components.base import JaxObject +from tidy3d.plugins.adjoint.components.simulation import JaxInfo, JaxSimulation + from .monitor_data import JAX_MONITOR_DATA_MAP, JaxMonitorDataType @@ -23,20 +24,20 @@ class JaxSimulationData(SimulationData, JaxObject): """A :class:`.SimulationData` registered with jax.""" - output_data: Tuple[JaxMonitorDataType, ...] = pd.Field( + output_data: tuple[JaxMonitorDataType, ...] = pd.Field( (), title="Jax Data", description="Tuple of Jax-compatible data associated with output monitors.", jax_field=True, ) - grad_data: Tuple[FieldData, ...] = pd.Field( + grad_data: tuple[FieldData, ...] = pd.Field( (), title="Gradient Field Data", description="Tuple of monitor data storing fields associated with the input structures.", ) - grad_eps_data: Tuple[PermittivityData, ...] = pd.Field( + grad_eps_data: tuple[PermittivityData, ...] = pd.Field( (), title="Gradient Permittivity Data", description="Tuple of monitor data storing epsilon associated with the input structures.", @@ -83,22 +84,22 @@ def get_poynting_vector(self, field_monitor_name: str) -> xr.Dataset: return super().get_poynting_vector(field_monitor_name) @property - def grad_data_symmetry(self) -> Tuple[FieldData, ...]: + def grad_data_symmetry(self) -> tuple[FieldData, ...]: """``self.grad_data`` but with ``symmetry_expanded_copy`` applied.""" return tuple(data.symmetry_expanded_copy for data in self.grad_data) @property - def grad_eps_data_symmetry(self) -> Tuple[FieldData, ...]: + def grad_eps_data_symmetry(self) -> tuple[FieldData, ...]: """``self.grad_eps_data`` but with ``symmetry_expanded_copy`` applied.""" return tuple(data.symmetry_expanded_copy for data in self.grad_eps_data) @property - def output_monitor_data(self) -> Dict[str, JaxMonitorDataType]: + def output_monitor_data(self) -> dict[str, JaxMonitorDataType]: """Dictionary of ``.output_data`` monitor ``.name`` to the corresponding data.""" return {monitor_data.monitor.name: monitor_data for monitor_data in self.output_data} @property - def monitor_data(self) -> Dict[str, Union[JaxMonitorDataType, MonitorDataType]]: + def monitor_data(self) -> dict[str, Union[JaxMonitorDataType, MonitorDataType]]: """Dictionary of ``.output_data`` monitor ``.name`` to the corresponding data.""" reg_mnt_data = {monitor_data.monitor.name: monitor_data for monitor_data in self.data} reg_mnt_data.update(self.output_monitor_data) @@ -106,8 +107,8 @@ def monitor_data(self) -> Dict[str, Union[JaxMonitorDataType, MonitorDataType]]: @staticmethod def split_data( - mnt_data: List[MonitorDataType], jax_info: JaxInfo - ) -> Dict[str, List[MonitorDataType]]: + mnt_data: list[MonitorDataType], jax_info: JaxInfo + ) -> dict[str, list[MonitorDataType]]: """Split list of monitor data into data, output_data, grad_data, and grad_eps_data.""" # Get information needed to split the full data list len_output_data = jax_info.num_output_monitors @@ -124,13 +125,16 @@ def split_data( ] grad_eps_data = all_data[len_data + len_output_data + len_grad_data :] - return dict( - data=data, output_data=output_data, grad_data=grad_data, grad_eps_data=grad_eps_data - ) + return { + "data": data, + "output_data": output_data, + "grad_data": grad_data, + "grad_eps_data": grad_eps_data, + } @classmethod def from_sim_data( - cls, sim_data: SimulationData, jax_info: JaxInfo, task_id: str = None + cls, sim_data: SimulationData, jax_info: JaxInfo, task_id: Optional[str] = None ) -> JaxSimulationData: """Construct a :class:`.JaxSimulationData` instance from a :class:`.SimulationData`.""" @@ -159,14 +163,14 @@ def from_sim_data( output_data_list.append(jax_mnt_data) data_dict["output_data"] = output_data_list self_dict.update(data_dict) - self_dict.update(dict(task_id=task_id)) + self_dict.update({"task_id": task_id}) return cls.parse_obj(self_dict) @classmethod def split_fwd_sim_data( cls, sim_data: SimulationData, jax_info: JaxInfo - ) -> Tuple[SimulationData, SimulationData]: + ) -> tuple[SimulationData, SimulationData]: """Split a :class:`.SimulationData` into two parts, containing user and gradient data.""" sim = sim_data.simulation @@ -230,14 +234,14 @@ def make_adjoint_simulation(self, fwidth: float, run_time: float) -> JaxSimulati # set a very short run time relative to the fwidth run_time = 2 / fwidth - update_dict = dict( - boundary_spec=bc_adj, - sources=adj_srcs, - monitors=(), - output_monitors=(), - run_time=run_time, - normalize_index=None, # normalize later, frequency-by-frequency - ) + update_dict = { + "boundary_spec": bc_adj, + "sources": adj_srcs, + "monitors": (), + "output_monitors": (), + "run_time": run_time, + "normalize_index": None, # normalize later, frequency-by-frequency + } update_dict.update( sim_fwd.get_grad_monitors( @@ -252,7 +256,7 @@ def make_adjoint_simulation(self, fwidth: float, run_time: float) -> JaxSimulati if len(sim_fwd.sources) and grid_spec_fwd.wavelength is None: wavelength_fwd = grid_spec_fwd.wavelength_from_sources(sim_fwd.sources) grid_spec_adj = grid_spec_fwd.updated_copy(wavelength=wavelength_fwd) - update_dict.update(dict(grid_spec=grid_spec_adj)) + update_dict.update({"grid_spec": grid_spec_adj}) return sim_fwd.updated_copy(**update_dict) @@ -272,7 +276,7 @@ def normalize_adjoint_fields(self) -> JaxSimulationData: spectrum_fn = self.source_spectrum(source_index) norm_factor_f[i] = complex(spectrum_fn([freq])[0]) - norm_factor_f_darr = xr.DataArray(norm_factor_f, coords=dict(f=freqs)) + norm_factor_f_darr = xr.DataArray(norm_factor_f, coords={"f": freqs}) field_component_norm = field_component / norm_factor_f_darr field_components_norm[field_name] = field_component_norm diff --git a/tidy3d/plugins/adjoint/components/geometry.py b/tidy3d/plugins/adjoint/components/geometry.py index 578d8f53aa..44f0424078 100644 --- a/tidy3d/plugins/adjoint/components/geometry.py +++ b/tidy3d/plugins/adjoint/components/geometry.py @@ -3,7 +3,7 @@ from __future__ import annotations from abc import ABC -from typing import Dict, List, Tuple, Union +from typing import Union import jax import jax.numpy as jnp @@ -14,21 +14,22 @@ from jax.tree_util import register_pytree_node_class from joblib import Parallel, delayed -from ....components.base import cached_property -from ....components.data.data_array import ScalarFieldDataArray -from ....components.data.monitor_data import FieldData, PermittivityData -from ....components.geometry.base import Box, Geometry, GeometryGroup -from ....components.geometry.polyslab import ( +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import ScalarFieldDataArray +from tidy3d.components.data.monitor_data import FieldData, PermittivityData +from tidy3d.components.geometry.base import Box, Geometry, GeometryGroup +from tidy3d.components.geometry.polyslab import ( _COMPLEX_POLYSLAB_DIVISIONS_WARN, _IS_CLOSE_RTOL, PolySlab, ) -from ....components.monitor import FieldMonitor, PermittivityMonitor -from ....components.types import ArrayFloat2D, Bound, Coordinate2D # , annotate_type -from ....constants import MICROMETER, fp_eps -from ....exceptions import AdjointError -from ....log import log -from ...polyslab import ComplexPolySlab +from tidy3d.components.monitor import FieldMonitor, PermittivityMonitor +from tidy3d.components.types import ArrayFloat2D, Bound, Coordinate2D # , annotate_type +from tidy3d.constants import MICROMETER, fp_eps +from tidy3d.exceptions import AdjointError +from tidy3d.log import log +from tidy3d.plugins.polyslab import ComplexPolySlab + from .base import WEB_ADJOINT_MESSAGE, JaxObject from .types import JaxFloat @@ -46,13 +47,13 @@ class JaxGeometry(Geometry, ABC): """Abstract :class:`.Geometry` with methods useful for all Jax subclasses.""" @property - def bound_size(self) -> Tuple[float, float, float]: + def bound_size(self) -> tuple[float, float, float]: """Size of the bounding box of this geometry.""" rmin, rmax = self.bounds return tuple(abs(pt_max - pt_min) for (pt_min, pt_max) in zip(rmin, rmax)) @property - def bound_center(self) -> Tuple[float, float, float]: + def bound_center(self) -> tuple[float, float, float]: """Size of the bounding box of this geometry.""" rmin, rmax = self.bounds @@ -76,8 +77,8 @@ def bounding_box(self): return JaxBox.from_bounds(*self.bounds) def make_grad_monitors( - self, freqs: List[float], name: str - ) -> Tuple[FieldMonitor, PermittivityMonitor]: + self, freqs: list[float], name: str + ) -> tuple[FieldMonitor, PermittivityMonitor]: """Return gradient monitor associated with this object.""" size_enlarged = tuple(s + 2 * GRAD_MONITOR_EXPANSION for s in self.bound_size) field_mnt = FieldMonitor( @@ -100,7 +101,7 @@ def make_grad_monitors( @staticmethod def compute_dotted_e_d_fields( grad_data_fwd: FieldData, grad_data_adj: FieldData, grad_data_eps: PermittivityData - ) -> Tuple[Dict[str, ScalarFieldDataArray], Dict[str, ScalarFieldDataArray]]: + ) -> tuple[dict[str, ScalarFieldDataArray], dict[str, ScalarFieldDataArray]]: """Get the (x,y,z) components of E_fwd * E_adj and D_fwd * D_adj fields in the domain.""" e_mult_xyz = {} @@ -133,7 +134,7 @@ class JaxBox(JaxGeometry, Box, JaxObject): _tidy3d_class = Box - center_jax: Tuple[JaxFloat, JaxFloat, JaxFloat] = pd.Field( + center_jax: tuple[JaxFloat, JaxFloat, JaxFloat] = pd.Field( (0.0, 0.0, 0.0), title="Center (Jax)", description="Jax traced value for the center of the box in (x, y, z).", @@ -141,7 +142,7 @@ class JaxBox(JaxGeometry, Box, JaxObject): stores_jax_for="center", ) - size_jax: Tuple[JaxFloat, JaxFloat, JaxFloat] = pd.Field( + size_jax: tuple[JaxFloat, JaxFloat, JaxFloat] = pd.Field( ..., title="Size (Jax)", description="Jax-traced value for the size of the box in (x, y, z).", @@ -266,7 +267,7 @@ def store_vjp( # convert surface vjps to center, size vjps. Note, convert these to jax types w/ np.sum() vjp_center = tuple(np.sum(vjp_surfs[dim][1] - vjp_surfs[dim][0]) for dim in "xyz") vjp_size = tuple(np.sum(0.5 * (vjp_surfs[dim][1] + vjp_surfs[dim][0])) for dim in "xyz") - return self.copy(update=dict(center_jax=vjp_center, size_jax=vjp_size)) + return self.copy(update={"center_jax": vjp_center, "size_jax": vjp_size}) @register_pytree_node_class @@ -275,7 +276,7 @@ class JaxPolySlab(JaxGeometry, PolySlab, JaxObject): _tidy3d_class = PolySlab - vertices_jax: Tuple[Tuple[JaxFloat, JaxFloat], ...] = pd.Field( + vertices_jax: tuple[tuple[JaxFloat, JaxFloat], ...] = pd.Field( ..., title="Vertices (Jax)", description="Jax-traced list of (d1, d2) defining the 2 dimensional positions of the " @@ -286,7 +287,7 @@ class JaxPolySlab(JaxGeometry, PolySlab, JaxObject): stores_jax_for="vertices", ) - slab_bounds_jax: Tuple[JaxFloat, JaxFloat] = pd.Field( + slab_bounds_jax: tuple[JaxFloat, JaxFloat] = pd.Field( ..., title="Slab bounds (Jax)", description="Jax-traced list of (h1, h2) defining the minimum and maximum positions " @@ -383,7 +384,7 @@ def _area(vertices: jnp.ndarray) -> float: @staticmethod def _shift_vertices( vertices: jnp.ndarray, dist - ) -> Tuple[jnp.ndarray, jnp.ndarray, Tuple[jnp.ndarray, jnp.ndarray]]: + ) -> tuple[jnp.ndarray, jnp.ndarray, tuple[jnp.ndarray, jnp.ndarray]]: """Shifts the vertices of a polygon outward uniformly by distances `dists`. @@ -468,7 +469,7 @@ def _neighbor_vertices_crossing_detection( return None @staticmethod - def _edge_length_and_reduction_rate(vertices: jnp.ndarray) -> Tuple[jnp.ndarray, jnp.ndarray]: + def _edge_length_and_reduction_rate(vertices: jnp.ndarray) -> tuple[jnp.ndarray, jnp.ndarray]: """Edge length of reduction rate of each edge with unit offset length. Parameters @@ -565,8 +566,8 @@ def edge_contrib( vertex_grad: Coordinate2D, vertex_stat: Coordinate2D, is_next: bool, - e_mult_xyz: Tuple[Dict[str, ScalarFieldDataArray]], - d_mult_xyz: Tuple[Dict[str, ScalarFieldDataArray]], + e_mult_xyz: tuple[dict[str, ScalarFieldDataArray]], + d_mult_xyz: tuple[dict[str, ScalarFieldDataArray]], sim_bounds: Bound, wvl_mat: float, eps_out: complex, @@ -606,8 +607,8 @@ def edge_position(s: np.array) -> np.array: return (1 - s) * vertex_stat[:, None] + s * vertex_grad[:, None] def edge_basis( - xyz_components: Tuple[FieldData, FieldData, FieldData], - ) -> Tuple[FieldData, FieldData, FieldData]: + xyz_components: tuple[FieldData, FieldData, FieldData], + ) -> tuple[FieldData, FieldData, FieldData]: """Puts a field component from the (x, y, z) basis to the (t, n, z) basis.""" cmp_z, (cmp_x_edge, cmp_y_edge) = self.pop_axis(xyz_components, axis=self.axis) @@ -623,7 +624,7 @@ def compute_integrand(s: np.array, z: np.array) -> np.array: x, y = edge_position(s=s) x = xr.DataArray(x, coords={"s": s}) y = xr.DataArray(y, coords={"s": s}) - coords_interp = dict(x=x, y=y, z=z) + coords_interp = {"x": x, "y": y, "z": z} def evaluate(scalar_field: ScalarFieldDataArray) -> float: """Evaluate a scalar field at a coordinate along the edge.""" @@ -696,8 +697,8 @@ def evaluate(scalar_field: ScalarFieldDataArray) -> float: def vertex_vjp( self, i_vertex, - e_mult_xyz: Tuple[Dict[str, ScalarFieldDataArray]], - d_mult_xyz: Tuple[Dict[str, ScalarFieldDataArray]], + e_mult_xyz: tuple[dict[str, ScalarFieldDataArray]], + d_mult_xyz: tuple[dict[str, ScalarFieldDataArray]], sim_bounds: Bound, wvl_mat: float, eps_out: complex, @@ -791,7 +792,7 @@ def _make_vertex_args( arg_list = [] for i in range(num_verts): - args_i = [i] + [e_mult_xyz, d_mult_xyz, sim_bounds, wvl_mat, eps_out, eps_in] + args_i = [i, e_mult_xyz, d_mult_xyz, sim_bounds, wvl_mat, eps_out, eps_in] arg_list.append(args_i) return arg_list @@ -870,7 +871,7 @@ def _dilation_value_at_reference_to_coord(self, dilation: float) -> float: return z_coord @property - def sub_polyslabs(self) -> List[JaxPolySlab]: + def sub_polyslabs(self) -> list[JaxPolySlab]: """Divide a complex polyslab into a list of simple polyslabs. Only neighboring vertex-vertex crossing events are treated in this version. @@ -992,7 +993,7 @@ class JaxGeometryGroup(JaxGeometry, GeometryGroup, JaxObject): _tidy3d_class = GeometryGroup - geometries: Tuple[JaxPolySlab, ...] = pd.Field( + geometries: tuple[JaxPolySlab, ...] = pd.Field( ..., title="Geometries", description="Tuple of jax geometries in a single grouping. " diff --git a/tidy3d/plugins/adjoint/components/medium.py b/tidy3d/plugins/adjoint/components/medium.py index f87a3ec9a2..75f506a8d4 100644 --- a/tidy3d/plugins/adjoint/components/medium.py +++ b/tidy3d/plugins/adjoint/components/medium.py @@ -3,19 +3,20 @@ from __future__ import annotations from abc import ABC -from typing import Callable, Dict, Optional, Tuple, Union +from typing import Callable, Literal, Optional, Union import numpy as np import pydantic.v1 as pd import xarray as xr from jax.tree_util import register_pytree_node_class -from ....components.data.monitor_data import FieldData -from ....components.geometry.base import Geometry -from ....components.medium import AnisotropicMedium, CustomMedium, Medium -from ....components.types import Bound, Literal -from ....constants import CONDUCTIVITY -from ....exceptions import SetupError +from tidy3d.components.data.monitor_data import FieldData +from tidy3d.components.geometry.base import Geometry +from tidy3d.components.medium import AnisotropicMedium, CustomMedium, Medium +from tidy3d.components.types import Bound +from tidy3d.constants import CONDUCTIVITY +from tidy3d.exceptions import SetupError + from .base import WEB_ADJOINT_MESSAGE, JaxObject from .data.data_array import JaxDataArray from .data.dataset import JaxPermittivityDataset @@ -33,7 +34,7 @@ class AbstractJaxMedium(ABC, JaxObject): def _get_volume_disc( self, grad_data: FieldData, sim_bounds: Bound, wvl_mat: float - ) -> Tuple[Dict[str, np.ndarray], float]: + ) -> tuple[dict[str, np.ndarray], float]: """Get the coordinates and volume element for the inside of the corresponding structure.""" # find intersecting volume between structure and simulation @@ -63,7 +64,7 @@ def _get_volume_disc( return vol_coords, d_vol @staticmethod - def make_inside_mask(vol_coords: Dict[str, np.ndarray], inside_fn: Callable) -> xr.DataArray: + def make_inside_mask(vol_coords: dict[str, np.ndarray], inside_fn: Callable) -> xr.DataArray: """Make a 3D mask of where the volume coordinates are inside a supplied function.""" meshgrid_args = [vol_coords[dim] for dim in "xyz" if dim in vol_coords] @@ -77,7 +78,7 @@ def e_mult_volume( field: Literal["Ex", "Ey", "Ez"], grad_data_fwd: FieldData, grad_data_adj: FieldData, - vol_coords: Dict[str, np.ndarray], + vol_coords: dict[str, np.ndarray], d_vol: float, inside_fn: Callable, ) -> xr.DataArray: @@ -188,10 +189,10 @@ def store_vjp( vjp_sigma += _vjp_sigma return self.copy( - update=dict( - permittivity_jax=vjp_eps, - conductivity_jax=vjp_sigma, - ) + update={ + "permittivity_jax": vjp_eps, + "conductivity_jax": vjp_sigma, + } ) @@ -444,7 +445,7 @@ def store_vjp( # package everything into dataset vjp_eps_dataset = JaxPermittivityDataset(**vjp_field_components) - return self.copy(update=dict(eps_dataset=vjp_eps_dataset)) + return self.copy(update={"eps_dataset": vjp_eps_dataset}) JaxMediumType = Union[JaxMedium, JaxAnisotropicMedium, JaxCustomMedium] diff --git a/tidy3d/plugins/adjoint/components/simulation.py b/tidy3d/plugins/adjoint/components/simulation.py index 93088536d4..3fcfdf0066 100644 --- a/tidy3d/plugins/adjoint/components/simulation.py +++ b/tidy3d/plugins/adjoint/components/simulation.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Literal, Tuple, Union +from typing import Literal, Optional, Union import numpy as np import pydantic.v1 as pd @@ -10,24 +10,25 @@ from jax.tree_util import register_pytree_node_class from joblib import Parallel, delayed -from ....components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ....components.data.monitor_data import FieldData, PermittivityData -from ....components.geometry.base import Box -from ....components.medium import AbstractMedium -from ....components.monitor import ( +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.data.monitor_data import FieldData, PermittivityData +from tidy3d.components.geometry.base import Box +from tidy3d.components.medium import AbstractMedium +from tidy3d.components.monitor import ( DiffractionMonitor, FieldMonitor, ModeMonitor, Monitor, PermittivityMonitor, ) -from ....components.simulation import Simulation -from ....components.structure import Structure -from ....components.subpixel_spec import Staircasing, SubpixelSpec -from ....components.types import Ax, annotate_type -from ....constants import HERTZ, SECOND -from ....exceptions import AdjointError -from ....log import log +from tidy3d.components.simulation import Simulation +from tidy3d.components.structure import Structure +from tidy3d.components.subpixel_spec import Staircasing, SubpixelSpec +from tidy3d.components.types import Ax, annotate_type +from tidy3d.constants import HERTZ, SECOND +from tidy3d.exceptions import AdjointError +from tidy3d.log import log + from .base import WEB_ADJOINT_MESSAGE, JaxObject from .geometry import JaxGeometryGroup, JaxPolySlab from .structure import ( @@ -61,7 +62,7 @@ ) OutputMonitorTypes = (DiffractionMonitor, FieldMonitor, ModeMonitor) -OutputMonitorType = Tuple[annotate_type(Union[OutputMonitorTypes]), ...] +OutputMonitorType = tuple[annotate_type(Union[OutputMonitorTypes]), ...] class JaxInfo(Tidy3dBaseModel): @@ -105,7 +106,7 @@ class JaxInfo(Tidy3dBaseModel): units=SECOND, ) - input_structure_types: Tuple[ + input_structure_types: tuple[ Literal["JaxStructure", "JaxStructureStaticMedium", "JaxStructureStaticGeometry"], ... ] = pd.Field( (), @@ -118,7 +119,7 @@ class JaxInfo(Tidy3dBaseModel): class JaxSimulation(Simulation, JaxObject): """A :class:`.Simulation` registered with jax.""" - input_structures: Tuple[annotate_type(JaxStructureType), ...] = pd.Field( + input_structures: tuple[annotate_type(JaxStructureType), ...] = pd.Field( (), title="Input Structures", description="Tuple of jax-compatible structures" @@ -132,13 +133,13 @@ class JaxSimulation(Simulation, JaxObject): description="Tuple of monitors whose data the differentiable output depends on.", ) - grad_monitors: Tuple[FieldMonitor, ...] = pd.Field( + grad_monitors: tuple[FieldMonitor, ...] = pd.Field( (), title="Gradient Field Monitors", description="Tuple of monitors used for storing fields, used internally for gradients.", ) - grad_eps_monitors: Tuple[PermittivityMonitor, ...] = pd.Field( + grad_eps_monitors: tuple[PermittivityMonitor, ...] = pd.Field( (), title="Gradient Permittivity Monitors", description="Tuple of monitors used for storing epsilon, used internally for gradients.", @@ -296,7 +297,7 @@ def _validate_web_adjoint(self) -> None: structure._validate_web_adjoint() @staticmethod - def get_freqs_adjoint(output_monitors: List[Monitor]) -> List[float]: + def get_freqs_adjoint(output_monitors: list[Monitor]) -> list[float]: """Return sorted list of unique frequencies stripped from a collection of monitors.""" if len(output_monitors) == 0: @@ -310,7 +311,7 @@ def get_freqs_adjoint(output_monitors: List[Monitor]) -> List[float]: return np.unique(output_freqs).tolist() @cached_property - def freqs_adjoint(self) -> List[float]: + def freqs_adjoint(self) -> list[float]: """Return sorted list of frequencies stripped from the output monitors.""" return self.get_freqs_adjoint(output_monitors=self.output_monitors) @@ -400,7 +401,7 @@ def num_time_steps_adjoint(self) -> int: """Number of time steps in the adjoint simulation.""" return len(self.tmesh_adjoint) - def to_simulation(self) -> Tuple[Simulation, JaxInfo]: + def to_simulation(self) -> tuple[Simulation, JaxInfo]: """Convert :class:`.JaxSimulation` instance to :class:`.Simulation` with an info dict.""" sim_dict = self.dict( @@ -419,7 +420,9 @@ def to_simulation(self) -> Tuple[Simulation, JaxInfo]: sim = Simulation.parse_obj(sim_dict) # put all structures and monitors in one list - all_structures = list(self.structures) + [js.to_structure() for js in self.input_structures] + all_structures = list(self.scene.sorted_structures) + [ + js.to_structure() for js in self.input_structures + ] all_monitors = ( list(self.monitors) + list(self.output_monitors) @@ -445,19 +448,19 @@ def to_simulation(self) -> Tuple[Simulation, JaxInfo]: def to_gds( self, cell, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pd.NonNegativeFloat = 1, frequency: pd.PositiveFloat = 0, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pd.NonNegativeInt, pd.NonNegativeInt] + gds_layer_dtype_map: Optional[ + dict[AbstractMedium, tuple[pd.NonNegativeInt, pd.NonNegativeInt]] ] = None, ) -> None: """Append the simulation structures to a .gds cell. Parameters ---------- - cell : ``gdstk.Cell`` or ``gdspy.Cell`` + cell : ``gdstk.Cell`` Cell object to which the generated polygons are added. x : float = None Position of plane in x direction, only one of x,y,z can be specified to define plane. @@ -486,15 +489,15 @@ def to_gds( def to_gdstk( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, permittivity_threshold: pd.NonNegativeFloat = 1, frequency: pd.PositiveFloat = 0, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pd.NonNegativeInt, pd.NonNegativeInt] + gds_layer_dtype_map: Optional[ + dict[AbstractMedium, tuple[pd.NonNegativeInt, pd.NonNegativeInt]] ] = None, - ) -> List: + ) -> list: """Convert a simulation's planar slice to a .gds type polygon list. Parameters ---------- @@ -526,44 +529,16 @@ def to_gdstk( gds_layer_dtype_map=gds_layer_dtype_map, ) - def to_gdspy( - self, - x: float = None, - y: float = None, - z: float = None, - gds_layer_dtype_map: Dict[ - AbstractMedium, Tuple[pd.NonNegativeInt, pd.NonNegativeInt] - ] = None, - ) -> List: - """Convert a simulation's planar slice to a .gds type polygon list. - Parameters - ---------- - x : float = None - Position of plane in x direction, only one of x,y,z can be specified to define plane. - y : float = None - Position of plane in y direction, only one of x,y,z can be specified to define plane. - z : float = None - Position of plane in z direction, only one of x,y,z can be specified to define plane. - gds_layer_dtype_map : Dict - Dictionary mapping mediums to GDSII layer and data type tuples. - Return - ------ - List - List of `gdspy.Polygon` and `gdspy.PolygonSet`. - """ - sim, _ = self.to_simulation() - return sim.to_gdspy(x=x, y=y, z=z, gds_layer_dtype_map=gds_layer_dtype_map) - def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - source_alpha: float = None, - monitor_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, **patch_kwargs, ) -> Ax: """Wrapper around regular :class:`.Simulation` structure plotting.""" @@ -582,15 +557,15 @@ def plot( def plot_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ax: Ax = None, ) -> Ax: """Wrapper around regular :class:`.Simulation` permittivity plotting.""" @@ -608,12 +583,12 @@ def plot_eps( def plot_structures( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. @@ -649,16 +624,16 @@ def plot_structures( def plot_structures_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, - hlim: Tuple[float, float] = None, - vlim: Tuple[float, float] = None, + hlim: Optional[tuple[float, float]] = None, + vlim: Optional[tuple[float, float]] = None, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. The permittivity is plotted in grayscale based on its value at the specified frequency. @@ -712,7 +687,7 @@ def epsilon( self, box: Box, coord_key: str = "centers", - freq: float = None, + freq: Optional[float] = None, ) -> xr.DataArray: """Get array of permittivity at volume specified by box and freq. @@ -753,7 +728,7 @@ def __eq__(self, other: JaxSimulation) -> bool: return self.to_simulation()[0] == other.to_simulation()[0] @classmethod - def split_monitors(cls, monitors: List[Monitor], jax_info: JaxInfo) -> Dict[str, Monitor]: + def split_monitors(cls, monitors: list[Monitor], jax_info: JaxInfo) -> dict[str, Monitor]: """Split monitors into user and adjoint required based on jax info.""" all_monitors = list(monitors) @@ -776,17 +751,17 @@ def split_monitors(cls, monitors: List[Monitor], jax_info: JaxInfo) -> Dict[str, grad_eps_monitors = all_monitors[num_mnts + num_output_monitors + num_grad_monitors :] # load into a dictionary - return dict( - monitors=monitors, - output_monitors=output_monitors, - grad_monitors=grad_monitors, - grad_eps_monitors=grad_eps_monitors, - ) + return { + "monitors": monitors, + "output_monitors": output_monitors, + "grad_monitors": grad_monitors, + "grad_eps_monitors": grad_eps_monitors, + } @classmethod def split_structures( - cls, structures: List[Structure], jax_info: JaxInfo - ) -> Dict[str, Structure]: + cls, structures: list[Structure], jax_info: JaxInfo + ) -> dict[str, Structure]: """Split structures into regular and input based on jax info.""" all_structures = list(structures) @@ -797,11 +772,11 @@ def split_structures( # split the list based on these numbers structures = all_structures[:num_structs] - structure_type_map = dict( - JaxStructure=JaxStructure, - JaxStructureStaticMedium=JaxStructureStaticMedium, - JaxStructureStaticGeometry=JaxStructureStaticGeometry, - ) + structure_type_map = { + "JaxStructure": JaxStructure, + "JaxStructureStaticMedium": JaxStructureStaticMedium, + "JaxStructureStaticGeometry": JaxStructureStaticGeometry, + } input_structures = [] for struct_type_str, struct in zip( @@ -812,7 +787,7 @@ def split_structures( input_structures.append(new_structure) # return a dictionary containing these split structures - return dict(structures=structures, input_structures=input_structures) + return {"structures": structures, "input_structures": input_structures} @classmethod def from_simulation(cls, simulation: Simulation, jax_info: JaxInfo) -> JaxSimulation: @@ -828,17 +803,17 @@ def from_simulation(cls, simulation: Simulation, jax_info: JaxInfo) -> JaxSimula sim_dict.update(**structures) sim_dict.update(**monitors) sim_dict.update( - dict( - fwidth_adjoint=jax_info.fwidth_adjoint, - run_time_adjoint=jax_info.run_time_adjoint, - ) + { + "fwidth_adjoint": jax_info.fwidth_adjoint, + "run_time_adjoint": jax_info.run_time_adjoint, + } ) # load JaxSimulation from the dictionary return cls.parse_obj(sim_dict) @classmethod - def make_sim_fwd(cls, simulation: Simulation, jax_info: JaxInfo) -> Tuple[Simulation, JaxInfo]: + def make_sim_fwd(cls, simulation: Simulation, jax_info: JaxInfo) -> tuple[Simulation, JaxInfo]: """Make the forward :class:`.JaxSimulation` from the supplied :class:`.Simulation`.""" mnt_dict = JaxSimulation.split_monitors(monitors=simulation.monitors, jax_info=jax_info) @@ -871,7 +846,7 @@ def make_sim_fwd(cls, simulation: Simulation, jax_info: JaxInfo) -> Tuple[Simula return sim_fwd, jax_info - def to_simulation_fwd(self) -> Tuple[Simulation, JaxInfo, JaxInfo]: + def to_simulation_fwd(self) -> tuple[Simulation, JaxInfo, JaxInfo]: """Like ``to_simulation()`` but the gradient monitors are included.""" simulation, jax_info = self.to_simulation() sim_fwd, jax_info_fwd = self.make_sim_fwd(simulation=simulation, jax_info=jax_info) @@ -879,7 +854,7 @@ def to_simulation_fwd(self) -> Tuple[Simulation, JaxInfo, JaxInfo]: @staticmethod def get_grad_monitors( - input_structures: List[Structure], freqs_adjoint: List[float], include_eps_mnts: bool = True + input_structures: list[Structure], freqs_adjoint: list[float], include_eps_mnts: bool = True ) -> dict: """Return dictionary of gradient monitors for simulation.""" grad_mnts = [] @@ -891,7 +866,7 @@ def get_grad_monitors( grad_mnts.append(grad_mnt) if include_eps_mnts: grad_eps_mnts.append(grad_eps_mnt) - return dict(grad_monitors=grad_mnts, grad_eps_monitors=grad_eps_mnts) + return {"grad_monitors": grad_mnts, "grad_eps_monitors": grad_eps_mnts} def _store_vjp_structure( self, @@ -916,9 +891,9 @@ def _store_vjp_structure( def store_vjp( self, - grad_data_fwd: Tuple[FieldData], - grad_data_adj: Tuple[FieldData], - grad_eps_data: Tuple[PermittivityData], + grad_data_fwd: tuple[FieldData], + grad_data_adj: tuple[FieldData], + grad_eps_data: tuple[PermittivityData], num_proc: int = NUM_PROC_LOCAL, ) -> JaxSimulation: """Store the vjp w.r.t. each input_structure as a sim using fwd and adj grad_data.""" @@ -939,25 +914,27 @@ def store_vjp( def store_vjp_sequential( self, - grad_data_fwd: Tuple[FieldData], - grad_data_adj: Tuple[FieldData], - grad_eps_data: Tuple[PermittivityData], + grad_data_fwd: tuple[FieldData], + grad_data_adj: tuple[FieldData], + grad_eps_data: tuple[PermittivityData], ) -> JaxSimulation: """Store the vjp w.r.t. each input_structure without multiprocessing.""" map_args = [self.input_structures, grad_data_fwd, grad_data_adj, grad_eps_data] input_structures_vjp = list(map(self._store_vjp_structure, *map_args)) return self.copy( - update=dict( - input_structures=input_structures_vjp, grad_monitors=(), grad_eps_monitors=() - ) + update={ + "input_structures": input_structures_vjp, + "grad_monitors": (), + "grad_eps_monitors": (), + } ) def store_vjp_parallel( self, - grad_data_fwd: Tuple[FieldData], - grad_data_adj: Tuple[FieldData], - grad_eps_data: Tuple[PermittivityData], + grad_data_fwd: tuple[FieldData], + grad_data_adj: tuple[FieldData], + grad_eps_data: tuple[PermittivityData], num_proc: int, ) -> JaxSimulation: """Store the vjp w.r.t. each input_structure as a sim using fwd and adj grad_data, and @@ -1014,7 +991,9 @@ def make_args(indexes, num_proc_internal) -> list: input_structures_vjp[index] = vjp return self.copy( - update=dict( - input_structures=input_structures_vjp, grad_monitors=(), grad_eps_monitors=() - ) + update={ + "input_structures": input_structures_vjp, + "grad_monitors": (), + "grad_eps_monitors": (), + } ) diff --git a/tidy3d/plugins/adjoint/components/structure.py b/tidy3d/plugins/adjoint/components/structure.py index d562816722..11c2276ca1 100644 --- a/tidy3d/plugins/adjoint/components/structure.py +++ b/tidy3d/plugins/adjoint/components/structure.py @@ -2,24 +2,25 @@ from __future__ import annotations -from typing import Dict, List, Union +from typing import Union import numpy as np import pydantic.v1 as pd from jax.tree_util import register_pytree_node_class -from ....components.data.monitor_data import FieldData, PermittivityData -from ....components.geometry.utils import GeometryType -from ....components.medium import MediumType -from ....components.monitor import FieldMonitor -from ....components.structure import Structure -from ....components.types import TYPE_TAG_STR, Bound -from ....constants import C_0 +from tidy3d.components.data.monitor_data import FieldData, PermittivityData +from tidy3d.components.geometry.utils import GeometryType +from tidy3d.components.medium import MediumType +from tidy3d.components.monitor import FieldMonitor +from tidy3d.components.structure import Structure +from tidy3d.components.types import TYPE_TAG_STR, Bound +from tidy3d.constants import C_0 + from .base import JaxObject from .geometry import JAX_GEOMETRY_MAP, JaxBox, JaxGeometryType from .medium import JAX_MEDIUM_MAP, JaxMediumType -GEO_MED_MAPPINGS = dict(geometry=JAX_GEOMETRY_MAP, medium=JAX_MEDIUM_MAP) +GEO_MED_MAPPINGS = {"geometry": JAX_GEOMETRY_MAP, "medium": JAX_MEDIUM_MAP} class AbstractJaxStructure(Structure, JaxObject): @@ -48,12 +49,12 @@ def _validate_web_adjoint(self) -> None: @property def jax_fields(self): """The fields that are jax-traced for this class.""" - return dict(geometry=self.geometry, medium=self.medium) + return {"geometry": self.geometry, "medium": self.medium} @property def exclude_fields(self): """Fields to exclude from the self dict.""" - return set(["type"] + list(self.jax_fields.keys())) + return {"type", *list(self.jax_fields.keys())} def to_structure(self) -> Structure: """Convert :class:`.JaxStructure` instance to :class:`.Structure`""" @@ -71,7 +72,7 @@ def from_structure(cls, structure: Structure) -> JaxStructure: struct_dict = structure.dict(exclude={"type"}) - jax_fields = dict(geometry=structure.geometry, medium=structure.medium) + jax_fields = {"geometry": structure.geometry, "medium": structure.medium} for key, component in jax_fields.items(): if key in cls._differentiable_fields: @@ -83,7 +84,7 @@ def from_structure(cls, structure: Structure) -> JaxStructure: return cls.parse_obj(struct_dict) - def make_grad_monitors(self, freqs: List[float], name: str) -> FieldMonitor: + def make_grad_monitors(self, freqs: list[float], name: str) -> FieldMonitor: """Return gradient monitor associated with this object.""" if "geometry" not in self._differentiable_fields: # make a fake JaxBox to be able to call .make_grad_monitors @@ -96,7 +97,7 @@ def make_grad_monitors(self, freqs: List[float], name: str) -> FieldMonitor: def _get_medium_params( self, grad_data_eps: PermittivityData, - ) -> Dict[str, float]: + ) -> dict[str, float]: """Compute params in the material of this structure.""" freq_max = float(max(grad_data_eps.eps_xx.f)) eps_in = self.medium.eps_model(frequency=freq_max) @@ -104,7 +105,7 @@ def _get_medium_params( ref_ind = max([1.0, abs(ref_ind)]) wvl_free_space = C_0 / freq_max wvl_mat = wvl_free_space / ref_ind - return dict(wvl_mat=wvl_mat, eps_in=eps_in) + return {"wvl_mat": wvl_mat, "eps_in": eps_in} def geometry_vjp( self, diff --git a/tidy3d/plugins/adjoint/components/types.py b/tidy3d/plugins/adjoint/components/types.py index fb1f01b580..9f191b4431 100644 --- a/tidy3d/plugins/adjoint/components/types.py +++ b/tidy3d/plugins/adjoint/components/types.py @@ -1,5 +1,7 @@ """Special types and validators used by adjoint plugin.""" +from __future__ import annotations + from typing import Any, Union import numpy as np @@ -32,10 +34,10 @@ class NumpyArrayType(np.ndarray): def __modify_schema__(cls, field_schema): """Sets the schema of np.ndarray object.""" - schema = dict( - title="npdarray", - type="numpy.ndarray", - ) + schema = { + "title": "npdarray", + "type": "numpy.ndarray", + } field_schema.update(schema) diff --git a/tidy3d/plugins/adjoint/utils/filter.py b/tidy3d/plugins/adjoint/utils/filter.py index 139aa5678b..29de7d9254 100644 --- a/tidy3d/plugins/adjoint/utils/filter.py +++ b/tidy3d/plugins/adjoint/utils/filter.py @@ -1,5 +1,7 @@ """Spatial filtering Functions for adjoint plugin.""" +from __future__ import annotations + from abc import ABC, abstractmethod import jax.numpy as jnp @@ -7,9 +9,9 @@ import numpy as np import pydantic.v1 as pd -from ....components.base import Tidy3dBaseModel -from ....constants import MICROMETER -from ....log import log +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.constants import MICROMETER +from tidy3d.log import log class Filter(Tidy3dBaseModel, ABC): diff --git a/tidy3d/plugins/adjoint/utils/penalty.py b/tidy3d/plugins/adjoint/utils/penalty.py index ae4892a3bf..6b736eec2a 100644 --- a/tidy3d/plugins/adjoint/utils/penalty.py +++ b/tidy3d/plugins/adjoint/utils/penalty.py @@ -1,14 +1,18 @@ """Penalty Functions for adjoint plugin.""" +from __future__ import annotations + from abc import ABC, abstractmethod +from typing import Optional import jax.numpy as jnp import pydantic.v1 as pd -from ....components.base import Tidy3dBaseModel -from ....components.types import ArrayFloat2D -from ....constants import MICROMETER -from ....log import log +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.types import ArrayFloat2D +from tidy3d.constants import MICROMETER +from tidy3d.log import log + from .filter import BinaryProjector, ConicFilter # Radius of Curvature Calculation @@ -227,7 +231,7 @@ def conic_filter(self) -> ConicFilter: """:class:`ConicFilter` associated with this object.""" return ConicFilter(radius=self.length_scale, design_region_dl=self.pixel_size) - def binary_projector(self, eta: float = None) -> BinaryProjector: + def binary_projector(self, eta: Optional[float] = None) -> BinaryProjector: """:class:`BinaryProjector` associated with this object.""" if eta is None: @@ -235,11 +239,11 @@ def binary_projector(self, eta: float = None) -> BinaryProjector: return BinaryProjector(eta=eta, beta=self.beta, vmin=0.0, vmax=1.0, strict_binarize=False) - def tanh_projection(self, x: jnp.ndarray, eta: float = None) -> jnp.ndarray: + def tanh_projection(self, x: jnp.ndarray, eta: Optional[float] = None) -> jnp.ndarray: """Project an array ``x`` once using ``self.beta`` and ``self.eta0``.""" return self.binary_projector(eta=eta).evaluate(x) - def filter_project(self, x: jnp.ndarray, eta: float = None) -> jnp.ndarray: + def filter_project(self, x: jnp.ndarray, eta: Optional[float] = None) -> jnp.ndarray: """Filter an array ``x`` using length scale and dL and then apply a projection.""" filter = self.conic_filter() projector = self.binary_projector(eta=eta) diff --git a/tidy3d/plugins/adjoint/web.py b/tidy3d/plugins/adjoint/web.py index f1031ed211..78182d9a69 100644 --- a/tidy3d/plugins/adjoint/web.py +++ b/tidy3d/plugins/adjoint/web.py @@ -1,24 +1,26 @@ """Adjoint-specific webapi.""" +from __future__ import annotations + import os import tempfile from functools import partial -from typing import Dict, List, Tuple +from typing import Optional import pydantic.v1 as pd from jax import custom_vjp from jax.tree_util import register_pytree_node_class import tidy3d as td +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.simulation import Simulation +from tidy3d.components.types import Literal from tidy3d.web.api.asynchronous import run_async as web_run_async +from tidy3d.web.api.container import DEFAULT_DATA_DIR, Batch, BatchData, Job from tidy3d.web.api.webapi import run as web_run from tidy3d.web.api.webapi import wait_for_connection from tidy3d.web.core.s3utils import download_file, upload_file -from ...components.data.sim_data import SimulationData -from ...components.simulation import Simulation -from ...components.types import Literal -from ...web.api.container import DEFAULT_DATA_DIR, Batch, BatchData, Job from .components.base import JaxObject from .components.data.sim_data import JaxSimulationData from .components.simulation import NUM_PROC_LOCAL, JaxInfo, JaxSimulation @@ -41,7 +43,7 @@ class RunResidual(JaxObject): class RunResidualBatch(JaxObject): """Class to store extra data needed to pass between the forward and backward adjoint run.""" - fwd_task_ids: Tuple[str, ...] = pd.Field( + fwd_task_ids: tuple[str, ...] = pd.Field( ..., title="Forward task_ids", description="task_ids of the forward simulations." ) @@ -50,7 +52,7 @@ class RunResidualBatch(JaxObject): class RunResidualAsync(JaxObject): """Class to store extra data needed to pass between the forward and backward adjoint run.""" - fwd_task_ids: Dict[str, str] = pd.Field( + fwd_task_ids: dict[str, str] = pd.Field( ..., title="Forward task_ids", description="task_ids of the forward simulation for async." ) @@ -70,7 +72,7 @@ def tidy3d_run_fn(simulation: Simulation, task_name: str, **kwargs) -> Simulatio return web_run(simulation=simulation, task_name=task_name, **kwargs) -def tidy3d_run_async_fn(simulations: Dict[str, Simulation], **kwargs) -> BatchData: +def tidy3d_run_async_fn(simulations: dict[str, Simulation], **kwargs) -> BatchData: """Run a set of regular :class:`.Simulation` objects after conversion from jax type.""" return web_run_async(simulations=simulations, **kwargs) @@ -83,7 +85,7 @@ def _run( task_name: str, folder_name: str = "default", path: str = "simulation_data.hdf5", - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, ) -> JaxSimulationData: """Split the provided ``JaxSimulation`` into a regular ``Simulation`` and a ``JaxInfo`` part, @@ -109,7 +111,7 @@ def run( task_name: str, folder_name: str = "default", path: str = "simulation_data.hdf5", - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, ) -> JaxSimulationData: """Submits a :class:`.JaxSimulation` to server, starts running, monitors progress, downloads, @@ -158,7 +160,7 @@ def run_fwd( path: str, callback_url: str, verbose: bool, -) -> Tuple[JaxSimulationData, Tuple[RunResidual]]: +) -> tuple[JaxSimulationData, tuple[RunResidual]]: """Run forward pass and stash extra objects for the backwards pass.""" simulation._validate_web_adjoint() @@ -191,7 +193,7 @@ def run_bwd( verbose: bool, res: tuple, sim_data_vjp: JaxSimulationData, -) -> Tuple[JaxSimulation]: +) -> tuple[JaxSimulation]: """Run backward pass and return simulation storing vjp of the objective w.r.t. the sim.""" fwd_task_id = res[0].fwd_task_id @@ -292,13 +294,13 @@ class AdjointBatch(Batch): description="Type of simulation, used internally only.", ) - jax_infos: Dict[str, JaxInfo] = pd.Field( + jax_infos: dict[str, JaxInfo] = pd.Field( ..., title="Jax Info Dict", description="Containers of information needed to reconstruct JaxSimulation for each item.", ) - jobs_cached: Dict[str, AdjointJob] = pd.Field( + jobs_cached: dict[str, AdjointJob] = pd.Field( None, title="Jobs (Cached)", description="Optional field to specify ``jobs``. Only used as a workaround internally " @@ -330,7 +332,7 @@ def webapi_run_adjoint_fwd( path: str, callback_url: str, verbose: bool, -) -> Dict[str, float]: +) -> dict[str, float]: """Runs the forward simulation on our servers, stores the gradient data for later.""" job = AdjointJob( @@ -390,13 +392,13 @@ def _task_name_orig(index: int): @partial(custom_vjp, nondiff_argnums=tuple(range(1, 6))) def run_async( - simulations: Tuple[JaxSimulation, ...], + simulations: tuple[JaxSimulation, ...], folder_name: str = "default", path_dir: str = DEFAULT_DATA_DIR, - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, - num_workers: int = None, -) -> Tuple[JaxSimulationData, ...]: + num_workers: Optional[int] = None, +) -> tuple[JaxSimulationData, ...]: """Submits a set of :class:`.JaxSimulation` objects to server, starts running, monitors progress, downloads, and loads results as a tuple of :class:`.JaxSimulationData` objects. @@ -464,13 +466,13 @@ def run_async( def run_async_fwd( - simulations: Tuple[JaxSimulation, ...], + simulations: tuple[JaxSimulation, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, num_workers: int, -) -> Tuple[Tuple[JaxSimulationData, ...], RunResidualBatch]: +) -> tuple[tuple[JaxSimulationData, ...], RunResidualBatch]: """Run forward pass and stash extra objects for the backwards pass.""" for simulation in simulations: @@ -514,8 +516,8 @@ def run_async_bwd( verbose: bool, num_workers: int, res: tuple, - batch_data_vjp: Tuple[JaxSimulationData, ...], -) -> Tuple[Dict[str, JaxSimulation]]: + batch_data_vjp: tuple[JaxSimulationData, ...], +) -> tuple[dict[str, JaxSimulation]]: """Run backward pass and return simulation storing vjp of the objective w.r.t. the sim.""" fwd_task_ids = res[0].fwd_task_ids @@ -553,13 +555,13 @@ def run_async_bwd( def webapi_run_async_adjoint_fwd( - simulations: Tuple[Simulation, ...], - jax_infos: Tuple[JaxInfo, ...], + simulations: tuple[Simulation, ...], + jax_infos: tuple[JaxInfo, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, -) -> Tuple[BatchData, Dict[str, str]]: +) -> tuple[BatchData, dict[str, str]]: """Runs the forward simulations on our servers, stores the gradient data for later.""" task_names = [str(_task_name_orig(i)) for i in range(len(simulations))] @@ -581,14 +583,14 @@ def webapi_run_async_adjoint_fwd( def webapi_run_async_adjoint_bwd( - simulations: Tuple[Simulation, ...], - jax_infos: Tuple[JaxInfo, ...], + simulations: tuple[Simulation, ...], + jax_infos: tuple[JaxInfo, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, - parent_tasks: List[List[str]], -) -> List[JaxSimulation]: + parent_tasks: list[list[str]], +) -> list[JaxSimulation]: """Runs the forward simulations on our servers, stores the gradient data for later.""" task_names = [str(i) for i in range(len(simulations))] @@ -632,7 +634,7 @@ def run_local( task_name: str, folder_name: str = "default", path: str = "simulation_data.hdf5", - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, num_proc: int = NUM_PROC_LOCAL, ) -> JaxSimulationData: @@ -690,7 +692,7 @@ def run_local_fwd( callback_url: str, verbose: bool, num_proc: int, -) -> Tuple[JaxSimulationData, tuple]: +) -> tuple[JaxSimulationData, tuple]: """Run forward pass and stash extra objects for the backwards pass.""" # add the gradient monitors and run the forward simulation @@ -708,7 +710,7 @@ def run_local_fwd( ) # remove the gradient data from the returned version (not needed) - sim_data_orig = sim_data_fwd.copy(update=dict(grad_data=(), simulation=simulation)) + sim_data_orig = sim_data_fwd.copy(update={"grad_data": (), "simulation": simulation}) return sim_data_orig, (sim_data_fwd,) @@ -721,7 +723,7 @@ def run_local_bwd( num_proc: int, res: tuple, sim_data_vjp: JaxSimulationData, -) -> Tuple[JaxSimulation]: +) -> tuple[JaxSimulation]: """Run backward pass and return simulation storing vjp of the objective w.r.t. the sim.""" # grab the forward simulation and its gradient monitor data @@ -764,7 +766,7 @@ def run_local_bwd( """ Running a batch of simulations using web.run_async. """ -def _task_name_orig_local(index: int, task_name_suffix: str = None): +def _task_name_orig_local(index: int, task_name_suffix: Optional[str] = None): """Task name as function of index into simulations. Note: for original must be int.""" if task_name_suffix is not None: return f"{index}{task_name_suffix}" @@ -773,14 +775,14 @@ def _task_name_orig_local(index: int, task_name_suffix: str = None): @partial(custom_vjp, nondiff_argnums=tuple(range(1, 7))) def run_async_local( - simulations: Tuple[JaxSimulation, ...], + simulations: tuple[JaxSimulation, ...], folder_name: str = "default", path_dir: str = DEFAULT_DATA_DIR, - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, - num_workers: int = None, - task_name_suffix: str = None, -) -> Tuple[JaxSimulationData, ...]: + num_workers: Optional[int] = None, + task_name_suffix: Optional[str] = None, +) -> tuple[JaxSimulationData, ...]: """Submits a set of :class:`.JaxSimulation` objects to server, starts running, monitors progress, downloads, and loads results as a tuple of :class:`.JaxSimulationData` objects. @@ -847,14 +849,14 @@ def run_async_local( def run_async_local_fwd( - simulations: Tuple[JaxSimulation, ...], + simulations: tuple[JaxSimulation, ...], folder_name: str, path_dir: str, callback_url: str, verbose: bool, num_workers: int, task_name_suffix: str, -) -> Tuple[Dict[str, JaxSimulationData], tuple]: +) -> tuple[dict[str, JaxSimulationData], tuple]: """Run forward pass and stash extra objects for the backwards pass.""" task_name_suffix_fwd = _task_name_fwd("") @@ -881,7 +883,7 @@ def run_async_local_fwd( batch_data_orig = [] for i, sim_data_fwd in enumerate(batch_data_fwd): sim_orig = simulations[i] - sim_data_orig = sim_data_fwd.copy(update=dict(grad_data=(), simulation=sim_orig)) + sim_data_orig = sim_data_fwd.copy(update={"grad_data": (), "simulation": sim_orig}) batch_data_orig.append(sim_data_orig) return batch_data_orig, (batch_data_fwd,) @@ -895,8 +897,8 @@ def run_async_local_bwd( num_workers: int, task_name_suffix: str, res: tuple, - batch_data_vjp: Tuple[JaxSimulationData, ...], -) -> Tuple[Dict[str, JaxSimulation]]: + batch_data_vjp: tuple[JaxSimulationData, ...], +) -> tuple[dict[str, JaxSimulation]]: """Run backward pass and return simulation storing vjp of the objective w.r.t. the sim.""" # grab the forward simulation and its gradient monitor data diff --git a/tidy3d/plugins/autograd/__init__.py b/tidy3d/plugins/autograd/__init__.py index 6f304ad43c..c4b9de15e4 100644 --- a/tidy3d/plugins/autograd/__init__.py +++ b/tidy3d/plugins/autograd/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .differential_operators import grad, value_and_grad from .functions import ( add_at, @@ -41,38 +43,38 @@ "ConicFilter", "ErosionDilationPenalty", "FilterAndProject", - "make_filter", - "make_conic_filter", - "make_circular_filter", - "grey_indicator", + "add_at", + "chain", "convolve", - "pad", - "ramp_projection", - "tanh_projection", - "make_erosion_dilation_penalty", - "make_curvature_penalty", - "make_filter_and_project", "gaussian_filter", - "interpolate_spline", - "make_kernel", "get_kernel_size_px", - "chain", + "grad", "grey_closing", "grey_dilation", "grey_erosion", + "grey_indicator", "grey_opening", + "interpn", + "interpolate_spline", + "least_squares", + "make_circular_filter", + "make_conic_filter", + "make_curvature_penalty", + "make_erosion_dilation_penalty", + "make_filter", + "make_filter_and_project", + "make_kernel", "morphological_gradient", "morphological_gradient_external", "morphological_gradient_internal", + "pad", + "ramp_projection", "rescale", - "threshold", - "value_and_grad", - "smooth_min", - "smooth_max", - "add_at", - "interpn", - "least_squares", - "grad", "scalar_objective", + "smooth_max", + "smooth_min", + "tanh_projection", + "threshold", "trapz", + "value_and_grad", ] diff --git a/tidy3d/plugins/autograd/constants.py b/tidy3d/plugins/autograd/constants.py index 062be8e5c5..9d4539d18c 100644 --- a/tidy3d/plugins/autograd/constants.py +++ b/tidy3d/plugins/autograd/constants.py @@ -1,2 +1,4 @@ +from __future__ import annotations + BETA_DEFAULT = 1.0 ETA_DEFAULT = 0.5 diff --git a/tidy3d/plugins/autograd/differential_operators.py b/tidy3d/plugins/autograd/differential_operators.py index f61ea58945..3bd92356eb 100644 --- a/tidy3d/plugins/autograd/differential_operators.py +++ b/tidy3d/plugins/autograd/differential_operators.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Callable from autograd.builtins import tuple as atuple @@ -9,8 +11,8 @@ from .utilities import scalar_objective __all__ = [ - "value_and_grad", "grad", + "value_and_grad", ] diff --git a/tidy3d/plugins/autograd/functions.py b/tidy3d/plugins/autograd/functions.py index 0cdb3c952b..34516e89a8 100644 --- a/tidy3d/plugins/autograd/functions.py +++ b/tidy3d/plugins/autograd/functions.py @@ -1,9 +1,16 @@ -from typing import Callable, Iterable, List, Literal, Tuple, Union +from __future__ import annotations + +from collections.abc import Iterable +from typing import Callable, Literal, Union import autograd.numpy as np +import numpy as onp from autograd import jacobian +from autograd.extend import defvjp, primitive from autograd.scipy.signal import convolve as convolve_ag from autograd.scipy.special import logsumexp +from autograd.tracer import getval +from numpy.lib.stride_tricks import sliding_window_view from numpy.typing import NDArray from tidy3d.components.autograd.functions import add_at, interpn, trapz @@ -11,26 +18,32 @@ from .types import PaddingType __all__ = [ - "interpn", - "trapz", "add_at", - "pad", "convolve", + "grey_closing", "grey_dilation", "grey_erosion", "grey_opening", - "grey_closing", + "interpn", "morphological_gradient", - "morphological_gradient_internal", "morphological_gradient_external", + "morphological_gradient_internal", + "pad", "rescale", - "threshold", - "smooth_min", "smooth_max", + "smooth_min", + "threshold", + "trapz", ] -def _pad_indices(n: int, pad_width: Tuple[int, int], *, mode: PaddingType) -> NDArray: +def _get_pad_indices( + n: int, + pad_width: tuple[int, int], + *, + mode: PaddingType, + numpy_module, +) -> NDArray: """Compute the indices to pad an array along a single axis based on the padding mode. Parameters @@ -41,6 +54,8 @@ def _pad_indices(n: int, pad_width: Tuple[int, int], *, mode: PaddingType) -> ND The number of values padded to the edges of the axis. mode : PaddingType The padding mode to use. + numpy_module : module + The numpy module to use (either `numpy` or `autograd.numpy`). Returns ------- @@ -49,75 +64,31 @@ def _pad_indices(n: int, pad_width: Tuple[int, int], *, mode: PaddingType) -> ND """ total_pad = sum(pad_width) if n == 0: - return np.zeros(total_pad, dtype=int) + return numpy_module.zeros(total_pad, dtype=int) - idx = np.arange(-pad_width[0], n + pad_width[1]) + idx = numpy_module.arange(-pad_width[0], n + pad_width[1]) - # Handle each padding mode if mode == "constant": return idx - if mode == "edge": - return np.clip(idx, 0, n - 1) - + return numpy_module.clip(idx, 0, n - 1) if mode == "reflect": period = 2 * n - 2 if n > 1 else 1 - idx = np.mod(idx, period) - return np.where(idx >= n, period - idx, idx) - + idx = numpy_module.mod(idx, period) + return numpy_module.where(idx >= n, period - idx, idx) if mode == "symmetric": period = 2 * n if n > 1 else 1 - idx = np.mod(idx, period) - return np.where(idx >= n, period - idx - 1, idx) - + idx = numpy_module.mod(idx, period) + return numpy_module.where(idx >= n, period - idx - 1, idx) if mode == "wrap": - return np.mod(idx, n) + return numpy_module.mod(idx, n) raise ValueError(f"Unsupported padding mode: {mode}") -def _pad_axis( - array: NDArray, - pad_width: Tuple[int, int], - axis: int, - *, - mode: PaddingType = "constant", - constant_value: float = 0.0, -) -> NDArray: - """Pad an array along a specified axis. - - Parameters - ---------- - array : np.ndarray - The input array to pad. - pad_width : Tuple[int, int] - The number of values padded to the edges of the axis. - axis : int - The axis along which to pad. - mode : PaddingType = "constant" - The padding mode to use. - constant_value : float = 0.0 - The constant value to pad with when mode is 'constant'. - - Returns - ------- - np.ndarray - The padded array. - """ - if mode == "constant": - padding = [(0, 0)] * array.ndim - padding[axis] = pad_width - return np.pad(array, padding, mode="constant", constant_values=constant_value) - - idx = _pad_indices(array.shape[axis], pad_width, mode=mode) - indexer = [slice(None)] * array.ndim - indexer[axis] = idx - return array[tuple(indexer)] - - def pad( array: NDArray, - pad_width: Union[int, Tuple[int, int]], + pad_width: Union[int, tuple[int, int]], *, mode: PaddingType = "constant", axis: Union[int, Iterable[int], None] = None, @@ -152,34 +123,32 @@ def pad( IndexError If an axis is out of range for the array dimensions. """ - # Normalize pad_width to a tuple of two elements pad_width = np.atleast_1d(pad_width) if pad_width.size > 2: raise ValueError(f"Padding width must have one or two elements, got {pad_width.size}.") pad_tuple = (pad_width[0], pad_width[0]) if pad_width.size == 1 else tuple(pad_width) - # Validate padding values if any(p < 0 for p in pad_tuple): raise ValueError("Padding must be non-negative.") if all(p == 0 for p in pad_tuple): return array - # Normalize and validate axes axes = range(array.ndim) if axis is None else [axis] if isinstance(axis, int) else axis axes = [ax + array.ndim if ax < 0 else ax for ax in axes] if any(ax < 0 or ax >= array.ndim for ax in axes): raise IndexError(f"Axis out of range for array with {array.ndim} dimensions.") - # Apply padding to each axis result = array for ax in axes: - result = _pad_axis( - result, - pad_tuple, - axis=ax, - mode=mode, - constant_value=constant_value, - ) + if mode == "constant": + padding = [(0, 0)] * result.ndim + padding[ax] = pad_tuple + result = np.pad(result, padding, mode="constant", constant_values=constant_value) + else: + idx = _get_pad_indices(result.shape[ax], pad_tuple, mode=mode, numpy_module=np) + indexer = [slice(None)] * result.ndim + indexer[ax] = idx + result = result[tuple(indexer)] return result @@ -188,7 +157,7 @@ def convolve( kernel: NDArray, *, padding: PaddingType = "constant", - axes: Union[Tuple[List[int], List[int]], None] = None, + axes: Union[tuple[list[int], list[int]], None] = None, mode: Literal["full", "valid", "same"] = "same", ) -> NDArray: """Convolve an array with a given kernel. @@ -235,9 +204,29 @@ def convolve( return convolve_ag(array, kernel, axes=axes, mode=mode) +def _get_footprint(size, structure, maxval): + """Helper to generate the morphological footprint from size or structure.""" + if size is None and structure is None: + raise ValueError("Either size or structure must be provided.") + if size is not None and structure is not None: + raise ValueError("Cannot specify both size and structure.") + if structure is None: + size_np = onp.atleast_1d(size) + shape = (size_np[0], size_np[-1]) if size_np.size > 1 else (size_np[0], size_np[0]) + nb = onp.zeros(shape) + else: + structure_np = getval(structure) + nb = onp.copy(structure_np) + nb[structure_np == 0] = -maxval + if nb.shape[0] % 2 == 0 or nb.shape[1] % 2 == 0: + raise ValueError(f"Structuring element dimensions must be odd, got {nb.shape}.") + return nb + + +@primitive def grey_dilation( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[int, tuple[int, int], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -249,10 +238,13 @@ def grey_dilation( ---------- array : np.ndarray The input array to perform grey dilation on. - size : Union[Union[int, Tuple[int, int]], None] = None + size : Union[Union[int, tuple[int, int]], None] = None The size of the structuring element. If None, `structure` must be provided. + If a single integer is provided, a square structuring element is created. + For 1D arrays, use a tuple (size, 1) or (1, size) for horizontal or vertical operations. structure : Union[np.ndarray, None] = None The structuring element. If None, `size` must be provided. + For 1D operations on 2D arrays, use a 2D structure with one dimension being 1. mode : PaddingType = "reflect" The padding mode to use. maxval : float = 1e4 @@ -266,32 +258,90 @@ def grey_dilation( Raises ------ ValueError - If both `size` and `structure` are None. + If both `size` and `structure` are None, or if the structuring element has even dimensions. """ - if size is None and structure is None: - raise ValueError("Either size or structure must be provided.") + nb = _get_footprint(size, structure, maxval) + h, w = nb.shape - if size is not None: - size = np.atleast_1d(size) - shape = (size[0], size[-1]) - nb = np.zeros(shape) - elif np.all(structure == 0): - nb = np.zeros_like(structure) - else: - nb = np.copy(structure) - nb[structure == 0] = -maxval + padded_array = pad(array, (h // 2, h // 2), mode=mode, axis=0) + padded_array = pad(padded_array, (w // 2, w // 2), mode=mode, axis=1) + + padded_array_np = getval(padded_array) + windows = sliding_window_view(padded_array_np, window_shape=(h, w)) + dilated_windows = windows + nb + return onp.max(dilated_windows, axis=(-2, -1)) + + +def _vjp_maker_dilation(ans, array, size=None, structure=None, *, mode="reflect", maxval=1e4): + """VJP for the custom grey_dilation primitive.""" + nb = _get_footprint(size, structure, maxval) h, w = nb.shape - bias = np.reshape(nb, (-1, 1, 1)) - kernel = np.reshape(np.eye(h * w), (h * w, h, w)) - array = convolve(array, kernel, axes=((0, 1), (1, 2)), padding=mode) + bias - return np.max(array, axis=0) + padded_array = pad(array, (h // 2, h // 2), mode=mode, axis=0) + padded_array = pad(padded_array, (w // 2, w // 2), mode=mode, axis=1) + + padded_array_np = getval(padded_array) + in_h, in_w = getval(array).shape + + windows = sliding_window_view(padded_array_np, window_shape=(h, w)) + dilated_windows = windows + nb + + output_reshaped = ans[..., None, None] + is_max_mask = (dilated_windows == output_reshaped).astype(onp.float64) + + # normalize the gradient for cases where multiple elements are the maximum. + # When multiple elements in a window equal the maximum value, the gradient + # is distributed equally among them. This ensures gradient conservation. + # Note: Values can never exceed maxval in the output since we add structure + # values (capped at maxval) to the input array values. + multiplicity = onp.sum(is_max_mask, axis=(-2, -1), keepdims=True) + is_max_mask /= onp.maximum(multiplicity, 1) + + def vjp(g): + g_reshaped = g[..., None, None] + grad_windows = g_reshaped * is_max_mask + + grad_padded = onp.zeros_like(padded_array_np) + + # create broadcastable indices for the scatter-add operation + i = onp.arange(in_h)[:, None, None, None] + j = onp.arange(in_w)[None, :, None, None] + u = onp.arange(h)[None, None, :, None] + v = onp.arange(w)[None, None, None, :] + + onp.add.at(grad_padded, (i + u, j + v), grad_windows) + + pad_h, pad_w = h // 2, w // 2 + + # for constant padding, we can just slice the gradient + if mode == "constant": + return grad_padded[pad_h : pad_h + in_h, pad_w : pad_w + in_w] + + # for other modes, we need to sum gradients from padded regions by unpadding each axis + grad_unpadded_w = onp.zeros((in_h + 2 * pad_h, in_w)) + padded_indices_w = _get_pad_indices(in_w, (pad_w, pad_w), mode=mode, numpy_module=onp) + row_indices_w = onp.arange(in_h + 2 * pad_h)[:, None] + onp.add.at(grad_unpadded_w, (row_indices_w, padded_indices_w), grad_padded) + + grad_unpadded_hw = onp.zeros((in_h, in_w)) + padded_indices_h = _get_pad_indices(in_h, (pad_h, pad_h), mode=mode, numpy_module=onp)[ + :, None + ] + col_indices_h = onp.arange(in_w)[None, :] + onp.add.at(grad_unpadded_hw, (padded_indices_h, col_indices_h), grad_unpadded_w) + + return grad_unpadded_hw + + return vjp + + +defvjp(grey_dilation, _vjp_maker_dilation, argnums=[0]) def grey_erosion( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -299,10 +349,12 @@ def grey_erosion( ) -> NDArray: """Perform grey erosion on an array. + This function is implemented via duality, calling `grey_dilation` internally. + Parameters ---------- array : np.ndarray - The input array to perform grey dilation on. + The input array to perform grey erosion on. size : Union[Union[int, Tuple[int, int]], None] = None The size of the structuring element. If None, `structure` must be provided. structure : Union[np.ndarray, None] = None @@ -315,37 +367,23 @@ def grey_erosion( Returns ------- np.ndarray - The result of the grey dilation operation. - - Raises - ------ - ValueError - If both `size` and `structure` are None. + The result of the grey erosion operation. """ - if size is None and structure is None: - raise ValueError("Either size or structure must be provided.") - - if size is not None: - size = np.atleast_1d(size) - shape = (size[0], size[-1]) - nb = np.zeros(shape) - elif np.all(structure == 0): - nb = np.zeros_like(structure) - else: - nb = np.copy(structure) - nb[structure == 0] = -maxval - - h, w = nb.shape - bias = np.reshape(nb, (-1, 1, 1)) - kernel = np.reshape(np.eye(h * w), (h * w, h, w)) - - array = convolve(array, kernel, axes=((0, 1), (1, 2)), padding=mode) - bias - return np.min(array, axis=0) + if structure is not None: + structure = structure[::-1, ::-1] + + return -grey_dilation( + -array, + size=size, + structure=structure, + mode=mode, + maxval=maxval, + ) def grey_opening( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -378,7 +416,7 @@ def grey_opening( def grey_closing( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -411,7 +449,7 @@ def grey_closing( def morphological_gradient( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -444,7 +482,7 @@ def morphological_gradient( def morphological_gradient_internal( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -475,7 +513,7 @@ def morphological_gradient_internal( def morphological_gradient_external( array: NDArray, - size: Union[Union[int, Tuple[int, int]], None] = None, + size: Union[Union[int, tuple[int, int]], None] = None, structure: Union[NDArray, None] = None, *, mode: PaddingType = "reflect", @@ -581,7 +619,7 @@ def threshold( def smooth_max( - x: NDArray, tau: float = 1.0, axis: Union[int, Tuple[int, ...], None] = None + x: NDArray, tau: float = 1.0, axis: Union[int, tuple[int, ...], None] = None ) -> float: """Compute the smooth maximum of an array using temperature parameter tau. @@ -603,7 +641,7 @@ def smooth_max( def smooth_min( - x: NDArray, tau: float = 1.0, axis: Union[int, Tuple[int, ...], None] = None + x: NDArray, tau: float = 1.0, axis: Union[int, tuple[int, ...], None] = None ) -> float: """Compute the smooth minimum of an array using temperature parameter tau. @@ -628,7 +666,7 @@ def least_squares( func: Callable[[NDArray, float], NDArray], x: NDArray, y: NDArray, - initial_guess: Tuple[float, ...], + initial_guess: tuple[float, ...], max_iterations: int = 100, tol: float = 1e-6, ) -> NDArray: diff --git a/tidy3d/plugins/autograd/invdes/__init__.py b/tidy3d/plugins/autograd/invdes/__init__.py index 080f7dba82..b3a312ef0e 100644 --- a/tidy3d/plugins/autograd/invdes/__init__.py +++ b/tidy3d/plugins/autograd/invdes/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .filters import ( CircularFilter, ConicFilter, @@ -11,17 +13,17 @@ from .projections import ramp_projection, tanh_projection __all__ = [ - "grey_indicator", "CircularFilter", "ConicFilter", + "ErosionDilationPenalty", + "FilterAndProject", + "grey_indicator", "make_circular_filter", "make_conic_filter", "make_curvature_penalty", "make_erosion_dilation_penalty", - "ErosionDilationPenalty", "make_filter", "make_filter_and_project", - "FilterAndProject", "ramp_projection", "tanh_projection", ] diff --git a/tidy3d/plugins/autograd/invdes/filters.py b/tidy3d/plugins/autograd/invdes/filters.py index 2bdf45e2bf..b8bb019563 100644 --- a/tidy3d/plugins/autograd/invdes/filters.py +++ b/tidy3d/plugins/autograd/invdes/filters.py @@ -1,8 +1,9 @@ from __future__ import annotations import abc +from collections.abc import Iterable from functools import lru_cache, partial -from typing import Annotated, Callable, Iterable, Tuple, Union +from typing import Annotated, Callable, Optional, Union import numpy as np import pydantic.v1 as pd @@ -11,16 +12,15 @@ import tidy3d as td from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.types import TYPE_TAG_STR - -from ..functions import convolve -from ..types import KernelType, PaddingType -from ..utilities import get_kernel_size_px, make_kernel +from tidy3d.plugins.autograd.functions import convolve +from tidy3d.plugins.autograd.types import KernelType, PaddingType +from tidy3d.plugins.autograd.utilities import get_kernel_size_px, make_kernel class AbstractFilter(Tidy3dBaseModel, abc.ABC): """An abstract class for creating and applying convolution filters.""" - kernel_size: Union[pd.PositiveInt, Tuple[pd.PositiveInt, ...]] = pd.Field( + kernel_size: Union[pd.PositiveInt, tuple[pd.PositiveInt, ...]] = pd.Field( ..., title="Kernel Size", description="Size of the kernel in pixels for each dimension." ) normalize: bool = pd.Field( @@ -32,7 +32,7 @@ class AbstractFilter(Tidy3dBaseModel, abc.ABC): @classmethod def from_radius_dl( - cls, radius: Union[float, Tuple[float, ...]], dl: Union[float, Tuple[float, ...]], **kwargs + cls, radius: Union[float, tuple[float, ...]], dl: Union[float, tuple[float, ...]], **kwargs ) -> AbstractFilter: """Create a filter from radius and grid spacing. @@ -125,10 +125,10 @@ def get_kernel(size_px: Iterable[int], normalize: bool) -> NDArray: def _get_kernel_size( - radius: Union[float, Tuple[float, ...]], - dl: Union[float, Tuple[float, ...]], - size_px: Union[int, Tuple[int, ...]], -) -> Tuple[int, ...]: + radius: Union[float, tuple[float, ...]], + dl: Union[float, tuple[float, ...]], + size_px: Union[int, tuple[int, ...]], +) -> tuple[int, ...]: """Determine the kernel size based on the provided radius, grid spacing, or size in pixels. Parameters @@ -156,18 +156,17 @@ def _get_kernel_size( "Both 'size_px' and 'radius' and 'dl' are provided. 'size_px' will take precedence." ) return (size_px,) if np.isscalar(size_px) else tuple(size_px) - elif radius is not None and dl is not None: + if radius is not None and dl is not None: kernel_size = get_kernel_size_px(radius=radius, dl=dl) return (kernel_size,) if np.isscalar(kernel_size) else tuple(kernel_size) - else: - raise ValueError("Either 'size_px' or both 'radius' and 'dl' must be provided.") + raise ValueError("Either 'size_px' or both 'radius' and 'dl' must be provided.") def make_filter( - radius: Union[float, Tuple[float, ...]] = None, - dl: Union[float, Tuple[float, ...]] = None, + radius: Optional[Union[float, tuple[float, ...]]] = None, + dl: Optional[Union[float, tuple[float, ...]]] = None, *, - size_px: Union[int, Tuple[int, ...]] = None, + size_px: Optional[Union[int, tuple[int, ...]]] = None, normalize: bool = True, padding: PaddingType = "reflect", filter_type: KernelType, diff --git a/tidy3d/plugins/autograd/invdes/misc.py b/tidy3d/plugins/autograd/invdes/misc.py index ea92c7828d..0221d35b3e 100644 --- a/tidy3d/plugins/autograd/invdes/misc.py +++ b/tidy3d/plugins/autograd/invdes/misc.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import autograd.numpy as np from numpy.typing import NDArray diff --git a/tidy3d/plugins/autograd/invdes/parametrizations.py b/tidy3d/plugins/autograd/invdes/parametrizations.py index 22ef6d6f61..a853fb0053 100644 --- a/tidy3d/plugins/autograd/invdes/parametrizations.py +++ b/tidy3d/plugins/autograd/invdes/parametrizations.py @@ -1,14 +1,14 @@ from __future__ import annotations -from typing import Callable, Tuple, Union +from typing import Callable, Optional, Union import pydantic.v1 as pd from numpy.typing import NDArray from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.plugins.autograd.constants import BETA_DEFAULT, ETA_DEFAULT +from tidy3d.plugins.autograd.types import KernelType, PaddingType -from ..constants import BETA_DEFAULT, ETA_DEFAULT -from ..types import KernelType, PaddingType from .filters import make_filter from .projections import tanh_projection @@ -16,13 +16,13 @@ class FilterAndProject(Tidy3dBaseModel): """A class that combines filtering and projection operations.""" - radius: Union[float, Tuple[float, ...]] = pd.Field( + radius: Union[float, tuple[float, ...]] = pd.Field( ..., title="Radius", description="The radius of the kernel." ) - dl: Union[float, Tuple[float, ...]] = pd.Field( + dl: Union[float, tuple[float, ...]] = pd.Field( ..., title="Grid Spacing", description="The grid spacing." ) - size_px: Union[int, Tuple[int, ...]] = pd.Field( + size_px: Union[int, tuple[int, ...]] = pd.Field( None, title="Size in Pixels", description="The size of the kernel in pixels." ) beta: pd.NonNegativeFloat = pd.Field( @@ -38,7 +38,9 @@ class FilterAndProject(Tidy3dBaseModel): "reflect", title="Padding", description="The padding mode to use." ) - def __call__(self, array: NDArray, beta: float = None, eta: float = None) -> NDArray: + def __call__( + self, array: NDArray, beta: Optional[float] = None, eta: Optional[float] = None + ) -> NDArray: """Apply the filter and projection to an input array. Parameters @@ -70,10 +72,10 @@ def __call__(self, array: NDArray, beta: float = None, eta: float = None) -> NDA def make_filter_and_project( - radius: Union[float, Tuple[float, ...]] = None, - dl: Union[float, Tuple[float, ...]] = None, + radius: Optional[Union[float, tuple[float, ...]]] = None, + dl: Optional[Union[float, tuple[float, ...]]] = None, *, - size_px: Union[int, Tuple[int, ...]] = None, + size_px: Optional[Union[int, tuple[int, ...]]] = None, beta: float = BETA_DEFAULT, eta: float = ETA_DEFAULT, filter_type: KernelType = "conic", diff --git a/tidy3d/plugins/autograd/invdes/penalties.py b/tidy3d/plugins/autograd/invdes/penalties.py index 9fc27d40ae..92eaac6e79 100644 --- a/tidy3d/plugins/autograd/invdes/penalties.py +++ b/tidy3d/plugins/autograd/invdes/penalties.py @@ -1,4 +1,6 @@ -from typing import Callable, Tuple, Union +from __future__ import annotations + +from typing import Callable, Optional, Union import autograd.numpy as np import pydantic.v1 as pd @@ -6,21 +8,21 @@ from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.types import ArrayFloat2D +from tidy3d.plugins.autograd.types import PaddingType -from ..types import PaddingType from .parametrizations import FilterAndProject class ErosionDilationPenalty(Tidy3dBaseModel): """A class that computes a penalty for erosion/dilation of a parameter map not being unity.""" - radius: Union[float, Tuple[float, ...]] = pd.Field( + radius: Union[float, tuple[float, ...]] = pd.Field( ..., title="Radius", description="The radius of the kernel." ) - dl: Union[float, Tuple[float, ...]] = pd.Field( + dl: Union[float, tuple[float, ...]] = pd.Field( ..., title="Grid Spacing", description="The grid spacing." ) - size_px: Union[int, Tuple[int, ...]] = pd.Field( + size_px: Union[int, tuple[int, ...]] = pd.Field( None, title="Size in Pixels", description="The size of the kernel in pixels." ) beta: pd.NonNegativeFloat = pd.Field( @@ -88,10 +90,10 @@ def _close(arr: NDArray): def make_erosion_dilation_penalty( - radius: Union[float, Tuple[float, ...]], - dl: Union[float, Tuple[float, ...]], + radius: Union[float, tuple[float, ...]], + dl: Union[float, tuple[float, ...]], *, - size_px: Union[int, Tuple[int, ...]] = None, + size_px: Optional[Union[int, tuple[int, ...]]] = None, beta: float = 20.0, eta: float = 0.5, delta_eta: float = 0.01, diff --git a/tidy3d/plugins/autograd/invdes/projections.py b/tidy3d/plugins/autograd/invdes/projections.py index 51ba088db9..91da5d8866 100644 --- a/tidy3d/plugins/autograd/invdes/projections.py +++ b/tidy3d/plugins/autograd/invdes/projections.py @@ -1,7 +1,9 @@ +from __future__ import annotations + import autograd.numpy as np from numpy.typing import NDArray -from ..constants import BETA_DEFAULT, ETA_DEFAULT +from tidy3d.plugins.autograd.constants import BETA_DEFAULT, ETA_DEFAULT def ramp_projection(array: NDArray, width: float = 0.1, center: float = 0.5) -> NDArray: diff --git a/tidy3d/plugins/autograd/primitives/__init__.py b/tidy3d/plugins/autograd/primitives/__init__.py index 7a04eb0993..1306e8b512 100644 --- a/tidy3d/plugins/autograd/primitives/__init__.py +++ b/tidy3d/plugins/autograd/primitives/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .interpolate import interpolate_spline from .misc import gaussian_filter diff --git a/tidy3d/plugins/autograd/primitives/interpolate.py b/tidy3d/plugins/autograd/primitives/interpolate.py index 5e83b59d35..ac5b6c2d4c 100644 --- a/tidy3d/plugins/autograd/primitives/interpolate.py +++ b/tidy3d/plugins/autograd/primitives/interpolate.py @@ -1,9 +1,10 @@ +from __future__ import annotations + from typing import Optional import numpy as np from autograd.extend import defvjp, primitive from numpy.typing import NDArray -from scipy.linalg import solve_banded from tidy3d.log import log @@ -367,6 +368,8 @@ def _solve_tridiagonal(lower: NDArray, diag: NDArray, upper: NDArray, rhs: NDArr np.ndarray Solution vector """ + from scipy.linalg import solve_banded + n = diag.size ab = np.zeros((3, n)) ab[0, 1:] = upper[:-1] @@ -606,13 +609,12 @@ def compute_spline_coeffs( """ if order == 1: return compute_linear_coefficients(x_points, y_points) - elif order == 2: + if order == 2: left_deriv = endpoint_derivatives[0] return compute_quadratic_coefficients(x_points, y_points, left_deriv) - elif order == 3: + if order == 3: return compute_spline_coefficients(x_points, y_points, endpoint_derivatives) - else: - raise NotImplementedError(f"Spline order '{order}' not implemented.") + raise NotImplementedError(f"Spline order '{order}' not implemented.") def evaluate_spline(x_points: NDArray, coeffs: tuple, x_eval: NDArray) -> NDArray: @@ -636,12 +638,11 @@ def evaluate_spline(x_points: NDArray, coeffs: tuple, x_eval: NDArray) -> NDArra if order == 1: return evaluate_linear_spline(x_points, coeffs, x_eval) - elif order == 2: + if order == 2: return evaluate_quadratic_spline(x_points, coeffs, x_eval) - elif order == 3: + if order == 3: return evaluate_cubic_spline(x_points, coeffs, x_eval) - else: - raise NotImplementedError(f"Spline order '{order}' not implemented.") + raise NotImplementedError(f"Spline order '{order}' not implemented.") def get_spline_derivatives_wrt_y( @@ -672,17 +673,16 @@ def get_spline_derivatives_wrt_y( """ if order == 1: return get_linear_derivative_wrt_y(x_points, y_points) - elif order == 2: + if order == 2: left_deriv = endpoint_derivatives[0] return get_quadratic_derivative_wrt_y(x_points, y_points, left_deriv) - elif order == 3: + if order == 3: return get_cubic_derivative_wrt_y(x_points, y_points, endpoint_derivatives) - else: - raise NotImplementedError(f"Derivatives for spline order '{order}' not implemented.") + raise NotImplementedError(f"Derivatives for spline order '{order}' not implemented.") @primitive -def interpolate_spline( +def _interpolate_spline( x_points: NDArray, y_points: NDArray, num_points: int, @@ -692,46 +692,9 @@ def interpolate_spline( """Primitive function to perform spline interpolation of a given order with optional endpoint derivatives. - Parameters - ---------- - x_points : np.ndarray - X coordinates of the data points (must be strictly monotonic) - y_points : np.ndarray - Y coordinates of the data points - num_points : int - Number of points in the output interpolation - order : int - Order of the spline (1=linear, 2=quadratic, 3=cubic) - endpoint_derivatives : tuple[float, float] = (None, None) - Derivatives at the endpoints (left, right) - Note: For order=1 (linear), all endpoint derivatives are ignored. - For order=2 (quadratic), only the left endpoint derivative is used. - For order=3 (cubic), both endpoint derivatives are used if provided. - - Returns - ------- - tuple[np.ndarray, np.ndarray] - Tuple of (x_interpolated, y_interpolated) values - - Examples - -------- - >>> import numpy as np - >>> x = np.array([0, 1, 2]) - >>> y = np.array([0, 1, 0]) - >>> # Linear interpolation - >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, order=1) - >>> print(y_interp) - [0. 0.5 1. 0.5 0. ] - - >>> # Quadratic interpolation with left endpoint derivative - >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, endpoint_derivatives=(0, None), order=2) - >>> print(np.round(y_interp, 3)) - [0. 0.75 1. 0.5 0. ] - - >>> # Cubic interpolation with both endpoint derivatives - >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, endpoint_derivatives=(0, 0), order=3) - >>> print(np.round(y_interp, 3)) - [0. 0.75 1. 0.75 0. ] + Autograd requires that arguments to primitives are passed in positionally. + ``interpolate_spline`` is the public-facing wrapper for this function, + which allows keyword arguments in case users pass in kwargs. """ if order not in (1, 2, 3): raise NotImplementedError(f"Spline order '{order}' not implemented.") @@ -810,4 +773,64 @@ def vjp(g): return vjp -defvjp(interpolate_spline, None, interpolate_spline_y_vjp) +defvjp(_interpolate_spline, None, interpolate_spline_y_vjp) + + +def interpolate_spline( + x_points: NDArray, + y_points: NDArray, + num_points: int, + order: int, + endpoint_derivatives: tuple[Optional[float], Optional[float]] = (None, None), +) -> tuple[NDArray, NDArray]: + """Differentiable spline interpolation of a given order + with optional endpoint derivatives. + + Parameters + ---------- + x_points : np.ndarray + X coordinates of the data points (must be strictly monotonic) + y_points : np.ndarray + Y coordinates of the data points + num_points : int + Number of points in the output interpolation + order : int + Order of the spline (1=linear, 2=quadratic, 3=cubic) + endpoint_derivatives : tuple[float, float] = (None, None) + Derivatives at the endpoints (left, right) + Note: For order=1 (linear), all endpoint derivatives are ignored. + For order=2 (quadratic), only the left endpoint derivative is used. + For order=3 (cubic), both endpoint derivatives are used if provided. + + Returns + ------- + tuple[np.ndarray, np.ndarray] + Tuple of (x_interpolated, y_interpolated) values + + Examples + -------- + >>> import numpy as np + >>> x = np.array([0, 1, 2]) + >>> y = np.array([0, 1, 0]) + >>> # Linear interpolation + >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, order=1) + >>> print(y_interp) + [0. 0.5 1. 0.5 0. ] + + >>> # Quadratic interpolation with left endpoint derivative + >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, endpoint_derivatives=(0, None), order=2) + >>> print(np.round(y_interp, 3)) + [0. 0.25 1. 1.25 0. ] + + >>> # Cubic interpolation with both endpoint derivatives + >>> x_interp, y_interp = interpolate_spline(x, y, num_points=5, endpoint_derivatives=(0, 0), order=3) + >>> print(np.round(y_interp, 3)) + [0. 0.5 1. 0.5 0. ] + """ + return _interpolate_spline( + x_points, + y_points, + num_points, + order, + endpoint_derivatives, + ) diff --git a/tidy3d/plugins/autograd/primitives/misc.py b/tidy3d/plugins/autograd/primitives/misc.py index c6f5bbfdfa..47932423de 100644 --- a/tidy3d/plugins/autograd/primitives/misc.py +++ b/tidy3d/plugins/autograd/primitives/misc.py @@ -1,8 +1,15 @@ +from __future__ import annotations + +import autograd.numpy as np import scipy.ndimage -from autograd.extend import defvjp, primitive +from autograd.extend import defjvp, defvjp, primitive gaussian_filter = primitive(scipy.ndimage.gaussian_filter) defvjp( gaussian_filter, lambda ans, x, *args, **kwargs: lambda g: gaussian_filter(g, *args, **kwargs), ) + +np.unwrap = primitive(np.unwrap) +defjvp(np.unwrap, lambda g, ans, x, *args, **kwargs: g) +defvjp(np.unwrap, lambda ans, x, *args, **kwargs: lambda g: g) diff --git a/tidy3d/plugins/autograd/types.py b/tidy3d/plugins/autograd/types.py index 1f98ebe077..3b842e2313 100644 --- a/tidy3d/plugins/autograd/types.py +++ b/tidy3d/plugins/autograd/types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Literal PaddingType = Literal["constant", "edge", "reflect", "symmetric", "wrap"] diff --git a/tidy3d/plugins/autograd/utilities.py b/tidy3d/plugins/autograd/utilities.py index 1303f9e1b6..7a7b5f83a8 100644 --- a/tidy3d/plugins/autograd/utilities.py +++ b/tidy3d/plugins/autograd/utilities.py @@ -1,5 +1,8 @@ +from __future__ import annotations + +from collections.abc import Iterable from functools import reduce, wraps -from typing import Any, Callable, Iterable, List, Union +from typing import Any, Callable, Optional, Union import autograd.numpy as anp import numpy as np @@ -83,8 +86,9 @@ def make_kernel(kernel_type: KernelType, size: Iterable[int], normalize: bool = def get_kernel_size_px( - radius: Union[float, Iterable[float]] = None, dl: Union[float, Iterable[float]] = None -) -> Union[int, List[int]]: + radius: Optional[Union[float, Iterable[float]]] = None, + dl: Optional[Union[float, Iterable[float]]] = None, +) -> Union[int, list[int]]: """Calculate the kernel size in pixels based on the provided radius and grid spacing. Parameters @@ -164,7 +168,7 @@ def chained(array: NDArray): return chained -def scalar_objective(func: Callable = None, *, has_aux: bool = False) -> Callable: +def scalar_objective(func: Optional[Callable] = None, *, has_aux: bool = False) -> Callable: """Decorator to ensure the objective function returns a real scalar value. This decorator wraps an objective function to ensure that its return value is a real scalar. @@ -202,8 +206,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: if has_aux: if not isinstance(result, tuple) or len(result) != 2: raise Tidy3dError( - "If 'has_aux' is True, the objective function must return " - "a tuple of length 2." + "If 'has_aux' is True, the objective function must return a tuple of length 2." ) result, aux_data = result @@ -223,7 +226,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: raise Tidy3dError( "An objective function's return value must be a scalar, " "a Python float/int, or an array containing a single element." - ) + ) from None except ValueError as e: # Result contains more than one element raise Tidy3dError( diff --git a/tidy3d/plugins/design/__init__.py b/tidy3d/plugins/design/__init__.py index 66b1da7ea5..e8bf9cc2cb 100644 --- a/tidy3d/plugins/design/__init__.py +++ b/tidy3d/plugins/design/__init__.py @@ -1,5 +1,7 @@ """Imports for parameter sweep.""" +from __future__ import annotations + from .design import DesignSpace from .method import ( MethodBayOpt, @@ -13,13 +15,13 @@ __all__ = [ "DesignSpace", - "ParameterInt", - "ParameterFloat", - "ParameterAny", - "Result", - "MethodMonteCarlo", - "MethodGrid", "MethodBayOpt", "MethodGenAlg", + "MethodGrid", + "MethodMonteCarlo", "MethodParticleSwarm", + "ParameterAny", + "ParameterFloat", + "ParameterInt", + "Result", ] diff --git a/tidy3d/plugins/design/design.py b/tidy3d/plugins/design/design.py index cf3333fcb4..2ea536e268 100644 --- a/tidy3d/plugins/design/design.py +++ b/tidy3d/plugins/design/design.py @@ -3,15 +3,16 @@ from __future__ import annotations import inspect -from typing import Any, Callable, Dict, List, Tuple, Union +from typing import Any, Callable, Optional, Union import pydantic.v1 as pd -from ...components.base import TYPE_TAG_STR, Tidy3dBaseModel, cached_property -from ...components.data.sim_data import SimulationData -from ...components.simulation import Simulation -from ...log import Console, get_logging_console, log -from ...web.api.container import Batch, BatchData, Job +from tidy3d.components.base import TYPE_TAG_STR, Tidy3dBaseModel, cached_property +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.simulation import Simulation +from tidy3d.log import Console, get_logging_console, log +from tidy3d.web.api.container import Batch, BatchData, Job + from .method import ( MethodBayOpt, MethodGenAlg, @@ -64,7 +65,7 @@ class DesignSpace(Tidy3dBaseModel): """ - parameters: Tuple[ParameterType, ...] = pd.Field( + parameters: tuple[ParameterType, ...] = pd.Field( (), title="Parameters", description="Set of parameters defining the dimensions and allowed values for the design space.", @@ -101,18 +102,18 @@ class DesignSpace(Tidy3dBaseModel): ) @cached_property - def dims(self) -> Tuple[str]: + def dims(self) -> tuple[str]: """dimensions defined by the design parameter names.""" return tuple(param.name for param in self.parameters) def _package_run_results( self, fn_args: list[dict[str, Any]], - fn_values: List[Any], + fn_values: list[Any], fn_source: str, - task_names: Tuple[str] = None, - task_paths: list = None, - aux_values: List[Any] = None, + task_names: Optional[tuple[str]] = None, + task_paths: Optional[list] = None, + aux_values: Optional[list[Any]] = None, opt_output: Any = None, ) -> Result: """How to package results from ``method.run`` and ``method.run_batch``""" @@ -142,7 +143,7 @@ def get_fn_source(function: Callable) -> str: except (TypeError, OSError): return None - def run(self, fn: Callable, fn_post: Callable = None, verbose: bool = True) -> Result: + def run(self, fn: Callable, fn_post: Optional[Callable] = None, verbose: bool = True) -> Result: """Explore a parameter space with a supplied method using the user supplied function. Supplied functions are used to evaluate the design space and are called within the method. For optimization methods these functions act as the fitness function. A single function can be @@ -245,12 +246,12 @@ def run(self, fn: Callable, fn_post: Callable = None, verbose: bool = True) -> R opt_output=opt_output, ) - def run_single(self, fn: Callable, console: Console) -> Tuple(list[dict], list, list[Any]): + def run_single(self, fn: Callable, console: Console) -> tuple(list[dict], list, list[Any]): """Run a single function of parameter inputs.""" evaluate_fn = self._get_evaluate_fn_single(fn=fn) return self.method._run(run_fn=evaluate_fn, parameters=self.parameters, console=console) - def run_pre_post(self, fn_pre: Callable, fn_post: Callable, console: Console) -> Tuple( + def run_pre_post(self, fn_pre: Callable, fn_post: Callable, console: Console) -> tuple( list[dict], list[dict], list[Any] ): """Run a function with Tidy3D implicitly called in between.""" @@ -356,8 +357,8 @@ def _find_and_map( _find_and_map(pre_out, Batch, batches, naming_keys) # Exit fn_mid here if no td computation is required - if not len(simulations) and not len(batches): - return original_pre_out, list(), list(), sim_counter + if not simulations and not batches: + return original_pre_out, [], [], sim_counter # Create task names for simulations named_sims = {} @@ -454,9 +455,9 @@ def _remove_or_replace(search_dict: dict, attr_name: str) -> dict: def run_batch( self, - fn_pre: Callable[Any, Union[Simulation, List[Simulation], Dict[str, Simulation]]], + fn_pre: Callable[Any, Union[Simulation, list[Simulation], dict[str, Simulation]]], fn_post: Callable[ - Union[SimulationData, List[SimulationData], Dict[str, SimulationData]], Any + Union[SimulationData, list[SimulationData], dict[str, SimulationData]], Any ], path_dir: str = ".", **batch_kwargs, @@ -560,10 +561,9 @@ def _estimate_sim_cost(sim): # For if tidy3d server cannot determine the estimate if per_run_estimate is None: return None - else: - return round(per_run_estimate * run_count, 3) + return round(per_run_estimate * run_count, 3) - def summarize(self, fn_pre: Callable = None, verbose: bool = True) -> dict[str, Any]: + def summarize(self, fn_pre: Optional[Callable] = None, verbose: bool = True) -> dict[str, Any]: """Summarize the setup of the DesignSpace Prints a summary of the DesignSpace including the method and associated args, the parameters, diff --git a/tidy3d/plugins/design/method.py b/tidy3d/plugins/design/method.py index 23fcafd217..22b0745bce 100644 --- a/tidy3d/plugins/design/method.py +++ b/tidy3d/plugins/design/method.py @@ -1,17 +1,20 @@ """Defines the methods used for parameter sweep.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Any, Callable, Dict, Literal, Tuple, Union +from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union import numpy as np import pydantic.v1 as pd -import scipy.stats.qmc as qmc -from ...components.base import Tidy3dBaseModel -from ...constants import inf +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.constants import inf + from .parameter import ParameterAny, ParameterFloat, ParameterInt, ParameterType -DEFAULT_MONTE_CARLO_SAMPLER_TYPE = qmc.LatinHypercube +if TYPE_CHECKING: + from scipy.stats import qmc as qmc_type class Method(Tidy3dBaseModel, ABC): @@ -20,11 +23,11 @@ class Method(Tidy3dBaseModel, ABC): name: str = pd.Field(None, title="Name", description="Optional name for the sweep method.") @abstractmethod - def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable) -> Tuple[Any]: + def _run(self, parameters: tuple[ParameterType, ...], run_fn: Callable) -> tuple[Any]: """Defines the search algorithm.""" @abstractmethod - def _get_run_count(self, parameters: list = None) -> int: + def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" def _force_int(self, next_point: dict, parameters: list) -> None: @@ -36,7 +39,7 @@ def _force_int(self, next_point: dict, parameters: list) -> None: next_point[param.name] = int(round(next_point[param.name], 0)) @staticmethod - def _extract_output(output: list, sampler: bool = False) -> Tuple: + def _extract_output(output: list, sampler: bool = False) -> tuple: """Format the user function output for further optimization and result storage.""" # Light check if all the outputs are the same type @@ -57,7 +60,7 @@ def _extract_output(output: list, sampler: bool = False) -> Tuple: none_aux = [None for _ in range(len(output))] return (output, none_aux) - if all(isinstance(val, (list, Tuple)) for val in output): + if all(isinstance(val, (list, tuple)) for val in output): if all(isinstance(val[0], (float, int)) for val in output): float_out = [] aux_out = [] @@ -73,16 +76,14 @@ def _extract_output(output: list, sampler: bool = False) -> Tuple: # Float with aux_out return (float_out, aux_out) - else: - raise ValueError( - "Unrecognized output from supplied post function. The first element in the iterable object should be a 'float'." - ) - - else: raise ValueError( - "Unrecognized output from supplied post function. Output should be a 'float' or an iterable object." + "Unrecognized output from supplied post function. The first element in the iterable object should be a 'float'." ) + raise ValueError( + "Unrecognized output from supplied post function. Output should be a 'float' or an iterable object." + ) + @staticmethod def _flatten_and_append(list_of_lists: list[list], append_target: list) -> None: """Flatten a list of lists and append the sublist to a new list.""" @@ -95,13 +96,13 @@ class MethodSample(Method, ABC): """A sweep method where all points are independently computed in one iteration.""" @abstractmethod - def sample(self, parameters: Tuple[ParameterType, ...], **kwargs) -> Dict[str, Any]: + def sample(self, parameters: tuple[ParameterType, ...], **kwargs) -> dict[str, Any]: """Defines how the design parameters are sampled.""" def _assemble_args( self, - parameters: Tuple[ParameterType, ...], - ) -> Tuple[dict, int]: + parameters: tuple[ParameterType, ...], + ) -> tuple[dict, int]: """Sample design parameters, check the args are hashable and compute number of points.""" fn_args = self.sample(parameters) @@ -109,7 +110,7 @@ def _assemble_args( self._force_int(arg_dict, parameters) return fn_args - def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) -> Tuple[Any]: + def _run(self, parameters: tuple[ParameterType, ...], run_fn: Callable, console) -> tuple[Any]: """Defines the search algorithm.""" # get all function inputs @@ -139,7 +140,7 @@ def _get_run_count(self, parameters: list) -> int: return len(self.sample(parameters)) @staticmethod - def sample(parameters: Tuple[ParameterType, ...]) -> Dict[str, Any]: + def sample(parameters: tuple[ParameterType, ...]) -> dict[str, Any]: """Defines how the design parameters are sampled on the grid.""" # sample each dimension individually @@ -230,11 +231,11 @@ class MethodBayOpt(MethodOptimize, ABC): description="The Xi coefficient used by the ``ei`` and ``poi`` acquisition functions. More detail available in the `package docs `_.", ) - def _get_run_count(self, parameters: list = None) -> int: + def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" return self.initial_iter + self.n_iter - def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) -> Tuple[Any]: + def _run(self, parameters: tuple[ParameterType, ...], run_fn: Callable, console) -> tuple[Any]: """Defines the Bayesian optimization search algorithm for the method. Uses the ``bayes_opt`` package to carry out a Bayesian optimization. Utilizes the ``.suggest`` and ``.register`` methods instead of @@ -247,7 +248,7 @@ def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) raise ImportError( "Cannot run Bayesian optimization as 'bayes_opt' module not found. " "Please check installation or run 'pip install bayesian-optimization==1.5.1'." - ) + ) from None # Identify non-numeric params and define boundaries for Bay-opt param_converter = {} @@ -429,13 +430,13 @@ class MethodGenAlg(MethodOptimize, ABC): # TODO: See if anyone is interested in having the full suite of PyGAD options - there's a lot! - def _get_run_count(self, parameters: list = None) -> int: + def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" # +1 to generations as pygad creates an initial population which is effectively "Generation 0" run_count = self.solutions_per_pop * (self.n_generations + 1) return run_count - def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) -> Tuple[Any]: + def _run(self, parameters: tuple[ParameterType, ...], run_fn: Callable, console) -> tuple[Any]: """Defines the genetic algorithm for the method. Uses the ``pygad`` package to carry out a particle search optimization. Additional development has ensured that @@ -447,7 +448,7 @@ def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) except ImportError: raise ImportError( "Cannot run genetic algorithm optimization as 'pygad' module not found. Please check installation or run 'pip install pygad'." - ) + ) from None # Make param names available to the fitness function param_keys = [param.name for param in parameters] @@ -475,7 +476,7 @@ def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) # Designed for str in ParameterAny but may work for anything param_converter[param.name] = self.any_to_int_param(param) - gene_spaces.append(range(0, len(param.allowed_values))) + gene_spaces.append(range(len(param.allowed_values))) gene_types.append(int) def capture_aux(sol_dict_list: list[dict]) -> None: @@ -680,11 +681,11 @@ class MethodParticleSwarm(MethodOptimize, ABC): description="Set the initial positions of the swarm using a numpy array of appropriate size.", ) - def _get_run_count(self, parameters: list = None) -> int: + def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" return self.n_particles * self.n_iter - def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) -> Tuple[Any]: + def _run(self, parameters: tuple[ParameterType, ...], run_fn: Callable, console) -> tuple[Any]: """Defines the particle search optimization algorithm for the method. Uses the ``pyswarms`` package to carry out a particle search optimization. @@ -695,7 +696,7 @@ def _run(self, parameters: Tuple[ParameterType, ...], run_fn: Callable, console) except ImportError: raise ImportError( "Cannot run particle swarm optimization as 'pyswarms' module not found. Please check installation or run 'pip install pyswarms'." - ) + ) from None # Pyswarms doesn't have a seed set outside of numpy std method if self.seed is not None: @@ -785,14 +786,14 @@ class AbstractMethodRandom(MethodSample, ABC): ) @abstractmethod - def _get_sampler(self, parameters: Tuple[ParameterType, ...]) -> qmc.QMCEngine: + def _get_sampler(self, parameters: tuple[ParameterType, ...]) -> qmc_type.QMCEngine: """Sampler for this ``Method`` class. If ``None``, sets a default.""" - def _get_run_count(self, parameters: list = None) -> int: + def _get_run_count(self, parameters: Optional[list] = None) -> int: """Return the maximum number of runs for the method based on current method arguments.""" return self.num_points - def sample(self, parameters: Tuple[ParameterType, ...], **kwargs) -> Dict[str, Any]: + def sample(self, parameters: tuple[ParameterType, ...], **kwargs) -> list[dict[str, Any]]: """Defines how the design parameters are sampled on grid.""" sampler = self._get_sampler(parameters) @@ -822,11 +823,12 @@ class MethodMonteCarlo(AbstractMethodRandom): >>> method = tdd.MethodMonteCarlo(num_points=20) """ - def _get_sampler(self, parameters: Tuple[ParameterType, ...]) -> qmc.QMCEngine: + def _get_sampler(self, parameters: tuple[ParameterType, ...]) -> qmc_type.QMCEngine: """Sampler for this ``Method`` class.""" + from scipy.stats import qmc d = len(parameters) - return DEFAULT_MONTE_CARLO_SAMPLER_TYPE(d=d, seed=self.seed) + return qmc.LatinHypercube(d=d, seed=self.seed) MethodType = Union[ diff --git a/tidy3d/plugins/design/parameter.py b/tidy3d/plugins/design/parameter.py index 77e5cf3c70..4d96646c2e 100644 --- a/tidy3d/plugins/design/parameter.py +++ b/tidy3d/plugins/design/parameter.py @@ -3,12 +3,12 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Any, List, Tuple, Union +from typing import Any, Union import numpy as np import pydantic.v1 as pd -from ...components.base import Tidy3dBaseModel +from tidy3d.components.base import Tidy3dBaseModel class Parameter(Tidy3dBaseModel, ABC): @@ -20,7 +20,7 @@ class Parameter(Tidy3dBaseModel, ABC): description="Unique name for the variable. Used as a key into the parameter sweep results.", ) - values: Tuple[Any, ...] = pd.Field( + values: tuple[Any, ...] = pd.Field( None, title="Custom Values", description="If specified, the parameter scan uses these values for grid search methods.", @@ -33,22 +33,22 @@ def _values_unique(cls, val): raise ValueError("Supplied 'values' were not unique.") return val - def sample_grid(self) -> List[Any]: + def sample_grid(self) -> list[Any]: """Sample design variable on grid, checking for custom values.""" if self.values is not None: return self.values return self._sample_grid() @abstractmethod - def sample_random(self, num_samples: int) -> List[Any]: + def sample_random(self, num_samples: int) -> list[Any]: """Sample this design variable randomly 'num_samples' times.""" @abstractmethod - def _sample_grid(self) -> List[Any]: + def _sample_grid(self) -> list[Any]: """Sample this design variable on a grid.""" @abstractmethod - def select_from_01(self, pts_01: np.ndarray) -> List[Any]: + def select_from_01(self, pts_01: np.ndarray) -> list[Any]: """Select values given a set of points between 0, 1.""" @abstractmethod @@ -59,7 +59,7 @@ def sample_first(self) -> Any: class ParameterNumeric(Parameter, ABC): """A variable with numeric values.""" - span: Tuple[Union[float, int], Union[float, int]] = pd.Field( + span: tuple[Union[float, int], Union[float, int]] = pd.Field( ..., title="Span", description="(min, max) range within which are allowed values for the variable. Is inclusive of max value.", @@ -109,21 +109,19 @@ def _span_is_float(cls, val): low, high = val return float(low), float(high) - def sample_random(self, num_samples: int) -> List[float]: + def sample_random(self, num_samples: int) -> list[float]: """Sample this design variable randomly 'num_samples' times.""" low, high = self.span return np.random.uniform(low=low, high=high, size=num_samples).tolist() - def _sample_grid(self) -> List[float]: + def _sample_grid(self) -> list[float]: """Sample this design variable on a grid.""" if self.num_points is None: - raise ValueError( - "'ParameterFloat' sampled on a grid must have '.num_points' defined." "" - ) + raise ValueError("'ParameterFloat' sampled on a grid must have '.num_points' defined.") low, high = self.span return np.linspace(low, high, self.num_points).tolist() - def select_from_01(self, pts_01: np.ndarray) -> List[Any]: + def select_from_01(self, pts_01: np.ndarray) -> list[Any]: """Select values given a set of points between 0, 1.""" return (min(self.span) + pts_01 * self.span_size).tolist() @@ -138,7 +136,7 @@ class ParameterInt(ParameterNumeric): >>> var = tdd.ParameterInt(name="x", span=(1, 4)) """ - span: Tuple[int, int] = pd.Field( + span: tuple[int, int] = pd.Field( ..., title="Span", description="``(min, max)`` range within which are allowed values for the variable. " @@ -152,17 +150,17 @@ def _span_is_int(cls, val): low, high = val return int(low), int(high) - def sample_random(self, num_samples: int) -> List[int]: + def sample_random(self, num_samples: int) -> list[int]: """Sample this design variable randomly 'num_samples' times.""" low, high = self.span return np.random.randint(low=low, high=high, size=num_samples).tolist() - def _sample_grid(self) -> List[float]: + def _sample_grid(self) -> list[float]: """Sample this design variable on a grid.""" low, high = self.span return np.arange(low, high).tolist() - def select_from_01(self, pts_01: np.ndarray) -> List[Any]: + def select_from_01(self, pts_01: np.ndarray) -> list[Any]: """Select values given a set of points between 0, 1.""" pts_continuous = min(self.span) + pts_01 * self.span_size return np.floor(pts_continuous).astype(int).tolist() @@ -177,7 +175,7 @@ class ParameterAny(Parameter): >>> var = tdd.ParameterAny(name="x", allowed_values=("a", "b", "c")) """ - allowed_values: Tuple[Any, ...] = pd.Field( + allowed_values: tuple[Any, ...] = pd.Field( ..., title="Allowed Values", description="The discrete set of values that this variable can take on.", @@ -197,15 +195,15 @@ def _no_duplicate_allowed_values(cls, val): raise ValueError("'allowed_values' has duplicate entries, must be unique.") return val - def sample_random(self, num_samples: int) -> List[Any]: + def sample_random(self, num_samples: int) -> list[Any]: """Sample this design variable randomly 'num_samples' times.""" return np.random.choice(self.allowed_values, size=int(num_samples)).tolist() - def _sample_grid(self) -> List[Any]: + def _sample_grid(self) -> list[Any]: """Sample this design variable uniformly, ie just take all allowed values.""" return list(self.allowed_values) - def select_from_01(self, pts_01: np.ndarray) -> List[Any]: + def select_from_01(self, pts_01: np.ndarray) -> list[Any]: """Select values given a set of points between 0, 1.""" pts_continuous = pts_01 * len(self.allowed_values) indices = np.floor(pts_continuous).astype(int) diff --git a/tidy3d/plugins/design/result.py b/tidy3d/plugins/design/result.py index 5f703cecfc..abf843183d 100644 --- a/tidy3d/plugins/design/result.py +++ b/tidy3d/plugins/design/result.py @@ -2,13 +2,13 @@ from __future__ import annotations -from typing import Any, Dict, List, Tuple +from typing import Any, Optional import numpy as np import pandas import pydantic.v1 as pd -from ...components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.base import Tidy3dBaseModel, cached_property # NOTE: Coords are args_dict from method and design. This may be changed in future to unify naming @@ -30,26 +30,26 @@ class Result(Tidy3dBaseModel): >>> # df.head() # print out first 5 elements of data """ - dims: Tuple[str, ...] = pd.Field( + dims: tuple[str, ...] = pd.Field( (), title="Dimensions", description="The dimensions of the design variables (indexed by 'name').", ) - values: Tuple[Any, ...] = pd.Field( + values: tuple[Any, ...] = pd.Field( (), title="Values", description="The return values from the design problem function.", ) - coords: Tuple[Tuple[Any, ...], ...] = pd.Field( + coords: tuple[tuple[Any, ...], ...] = pd.Field( (), title="Coordinates", description="The values of the coordinates corresponding to each of the dims." "Note: shaped (D, N) where D is the ``len(dims)`` and N is the ``len(values)``", ) - output_names: Tuple[str, ...] = pd.Field( + output_names: tuple[str, ...] = pd.Field( None, title="Output Names", description="Names for each of the outputs stored in ``values``. If not specified, default " @@ -78,7 +78,7 @@ class Result(Tidy3dBaseModel): "Stored in the same format as the output of fn_pre i.e. if pre outputs a dict, this output is a dict with the keys preserved.", ) - aux_values: Tuple[Any, ...] = pd.Field( + aux_values: tuple[Any, ...] = pd.Field( None, title="Auxiliary values output from the user function", description="The auxiliary return values from the design problem function. This is the collection of objects returned " @@ -99,7 +99,7 @@ def _coords_and_dims_shape(cls, val, values): dims = values.get("dims") if val is None or dims is None: - return + return None num_dims = len(dims) for i, _val in enumerate(val): @@ -118,7 +118,7 @@ def _coords_and_values_shape(cls, val, values): _values = values.get("values") if val is None or _values is None: - return + return None num_values = len(_values) num_coords = len(val) @@ -131,7 +131,7 @@ def _coords_and_values_shape(cls, val, values): return val - def value_as_dict(self, value) -> Dict[str, Any]: + def value_as_dict(self, value) -> dict[str, Any]: """How to convert an output function value as a dictionary.""" if isinstance(value, dict): return value @@ -141,7 +141,7 @@ def value_as_dict(self, value) -> Dict[str, Any]: return dict(zip(keys, value)) @staticmethod - def default_value_keys(value) -> Tuple[str, ...]: + def default_value_keys(value) -> tuple[str, ...]: """The default keys for a given value.""" # if a dict already, just use the existing keys as labels @@ -155,7 +155,7 @@ def default_value_keys(value) -> Tuple[str, ...]: # if simply single value (float, int, bool, etc) just label "output" return ("output",) - def items(self) -> Tuple[dict, Any]: + def items(self) -> tuple[dict, Any]: """Iterate through coordinates (args) and values (outputs) one by one.""" for coord_tuple, val in zip(self.coords, self.values): @@ -163,7 +163,7 @@ def items(self) -> Tuple[dict, Any]: yield coord_dict, val @cached_property - def data(self) -> Dict[tuple, Any]: + def data(self) -> dict[tuple, Any]: """Dict mapping tuple of fn args to their value.""" result = {} @@ -235,18 +235,18 @@ def to_dataframe(self, include_aux: bool = False) -> pandas.DataFrame: df = pandas.DataFrame(data=data, columns=columns) - attrs = dict( - task_names=self.task_names, - output_names=self.output_names, - fn_source=self.fn_source, - dims=self.dims, - ) + attrs = { + "task_names": self.task_names, + "output_names": self.output_names, + "fn_source": self.fn_source, + "dims": self.dims, + } df.attrs = attrs return df @classmethod - def from_dataframe(cls, df: pandas.DataFrame, dims: List[str] = None) -> Result: + def from_dataframe(cls, df: pandas.DataFrame, dims: Optional[list[str]] = None) -> Result: """Load a result directly from a `pandas.DataFrame` object. Parameters @@ -346,14 +346,14 @@ def __add__(self, other): """Special syntax for design_result1 + design_result2.""" return self.combine(other) - def get_index(self, fn_args: Dict[str, float]) -> int: + def get_index(self, fn_args: dict[str, float]) -> int: """Get index into the data for a specific set of arguments.""" key_list = list(self.coords) arg_key = tuple(fn_args[dim] for dim in self.dims) return key_list.index(arg_key) - def delete(self, fn_args: Dict[str, float]) -> Result: + def delete(self, fn_args: dict[str, float]) -> Result: """Delete a specific set of arguments from the result. Parameters @@ -392,7 +392,7 @@ def delete(self, fn_args: Dict[str, float]) -> Result: return self.updated_copy(values=new_values, coords=new_coords) - def add(self, fn_args: Dict[str, float], value: Any) -> Result: + def add(self, fn_args: dict[str, float], value: Any) -> Result: """Add a specific argument and value the result. Parameters @@ -408,8 +408,8 @@ def add(self, fn_args: Dict[str, float], value: Any) -> Result: Copy of the result with that element added. """ - new_values = list(self.values) + [value] - new_coords = list(self.coords) + [tuple(fn_args[dim] for dim in self.dims)] + new_values = [*list(self.values), value] + new_coords = [*list(self.coords), tuple(fn_args[dim] for dim in self.dims)] # ParticleSwarm optimizer doesn't work with updated_copy # Creating new result with updated values and coords instead diff --git a/tidy3d/plugins/dispersion/__init__.py b/tidy3d/plugins/dispersion/__init__.py index 2c6f10b3e5..33a76b4ee8 100644 --- a/tidy3d/plugins/dispersion/__init__.py +++ b/tidy3d/plugins/dispersion/__init__.py @@ -1,13 +1,15 @@ """Imports from dispersion fitter plugin.""" +from __future__ import annotations + from .fit import DispersionFitter from .fit_fast import AdvancedFastFitterParam, FastDispersionFitter from .web import AdvancedFitterParam, StableDispersionFitter __all__ = [ - "DispersionFitter", + "AdvancedFastFitterParam", "AdvancedFitterParam", - "StableDispersionFitter", + "DispersionFitter", "FastDispersionFitter", - "AdvancedFastFitterParam", + "StableDispersionFitter", ] diff --git a/tidy3d/plugins/dispersion/fit.py b/tidy3d/plugins/dispersion/fit.py index 24d318fa12..b9977e08b2 100644 --- a/tidy3d/plugins/dispersion/fit.py +++ b/tidy3d/plugins/dispersion/fit.py @@ -4,24 +4,22 @@ import codecs import csv -from typing import List, Optional, Tuple +from typing import Optional import numpy as np import requests -import scipy.optimize as opt from pydantic.v1 import Field, validator from rich.progress import Progress +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.medium import AbstractMedium, PoleResidue +from tidy3d.components.types import ArrayFloat1D, Ax +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import C_0, HBAR, MICROMETER +from tidy3d.exceptions import SetupError, ValidationError, WebError +from tidy3d.log import get_logging_console, log from tidy3d.web.core.environment import Env -from ...components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ...components.medium import AbstractMedium, PoleResidue -from ...components.types import ArrayFloat1D, Ax -from ...components.viz import add_ax_if_none -from ...constants import C_0, HBAR, MICROMETER -from ...exceptions import SetupError, ValidationError, WebError -from ...log import get_logging_console, log - class DispersionFitter(Tidy3dBaseModel): """Tool for fitting refractive index data to get a @@ -46,7 +44,7 @@ class DispersionFitter(Tidy3dBaseModel): description="Imaginary part of the complex index of refraction.", ) - wvl_range: Tuple[Optional[float], Optional[float]] = Field( + wvl_range: tuple[Optional[float], Optional[float]] = Field( (None, None), title="Wavelength range [wvl_min,wvl_max] for fitting", description="Truncate the wavelength, n and k data to the wavelength range '[wvl_min, " @@ -82,7 +80,7 @@ def _kdata_setup_and_length_match(cls, val, values): return val @cached_property - def data_in_range(self) -> Tuple[ArrayFloat1D, ArrayFloat1D, ArrayFloat1D]: + def data_in_range(self) -> tuple[ArrayFloat1D, ArrayFloat1D, ArrayFloat1D]: """Filter the wavelength-nk data to wavelength range for fitting. Returns @@ -129,7 +127,7 @@ def eps_data(self) -> complex: return AbstractMedium.nk_to_eps_complex(n=n_data, k=k_data) @property - def freqs(self) -> Tuple[float, ...]: + def freqs(self) -> tuple[float, ...]: """Convert filtered input wavelength data to frequency. Returns @@ -142,7 +140,7 @@ def freqs(self) -> Tuple[float, ...]: return C_0 / wvl_um @property - def frequency_range(self) -> Tuple[float, float]: + def frequency_range(self) -> tuple[float, float]: """Frequency range of filtered input data Returns @@ -262,7 +260,7 @@ def fit( num_tries: int = 50, tolerance_rms: float = 1e-2, guess: PoleResidue = None, - ) -> Tuple[PoleResidue, float]: + ) -> tuple[PoleResidue, float]: """Fit data a number of times and returns best results. Parameters @@ -347,7 +345,7 @@ def _fit_single( self, num_poles: int = 3, guess: PoleResidue = None, - ) -> Tuple[PoleResidue, float]: + ) -> tuple[PoleResidue, float]: """Perform a single fit to the data and return optimization result. Parameters @@ -362,6 +360,7 @@ def _fit_single( Tuple[:class:`.PoleResidue`, float] Results of single fit: (dispersive medium, RMS error). """ + import scipy.optimize as opt # NOTE: Not used def constraint(coeffs, _grad=None): @@ -460,7 +459,7 @@ def objective(coeffs, _grad=None): constraints=(scipy_constraint,), tol=1e-7, callback=None, - options=dict(maxiter=10000), + options={"maxiter": 10000}, ) coeffs = res.x @@ -557,7 +556,7 @@ def plot( return ax @staticmethod - def _validate_url_load(data_load: List): + def _validate_url_load(data_load: list): """Validate if the loaded data from URL is valid The data list should be in this format: [["wl", "n"], @@ -753,7 +752,7 @@ def from_complex_permittivity( wvl_um: ArrayFloat1D, eps_real: ArrayFloat1D, eps_imag: ArrayFloat1D = None, - wvl_range: Tuple[Optional[float], Optional[float]] = (None, None), + wvl_range: tuple[Optional[float], Optional[float]] = (None, None), ) -> DispersionFitter: """Loads :class:`DispersionFitter` from wavelength and complex relative permittivity data @@ -785,7 +784,7 @@ def from_loss_tangent( wvl_um: ArrayFloat1D, eps_real: ArrayFloat1D, loss_tangent: ArrayFloat1D, - wvl_range: Tuple[Optional[float], Optional[float]] = (None, None), + wvl_range: tuple[Optional[float], Optional[float]] = (None, None), ) -> DispersionFitter: """Loads :class:`DispersionFitter` from wavelength and loss tangent data. diff --git a/tidy3d/plugins/dispersion/fit_fast.py b/tidy3d/plugins/dispersion/fit_fast.py index 10564093ea..356dbde0a9 100644 --- a/tidy3d/plugins/dispersion/fit_fast.py +++ b/tidy3d/plugins/dispersion/fit_fast.py @@ -2,14 +2,19 @@ from __future__ import annotations -from typing import Tuple +from typing import Optional import numpy as np from pydantic.v1 import NonNegativeFloat, PositiveInt -from ...components.dispersion_fitter import AdvancedFastFitterParam, fit -from ...components.medium import PoleResidue -from ...constants import C_0, HBAR +from tidy3d.components.dispersion_fitter import ( + AdvancedFastFitterParam, + constant_loss_tangent_model, + fit, +) +from tidy3d.components.medium import PoleResidue +from tidy3d.constants import HBAR + from .fit import DispersionFitter # numerical tolerance for pole relocation for fast fitter @@ -41,10 +46,10 @@ def fit( self, min_num_poles: PositiveInt = 1, max_num_poles: PositiveInt = DEFAULT_MAX_POLES, - eps_inf: float = None, + eps_inf: Optional[float] = None, tolerance_rms: NonNegativeFloat = DEFAULT_TOLERANCE_RMS, advanced_param: AdvancedFastFitterParam = None, - ) -> Tuple[PoleResidue, float]: + ) -> tuple[PoleResidue, float]: """Fit data using a fast fitting algorithm. Note @@ -117,10 +122,11 @@ def constant_loss_tangent_model( cls, eps_real: float, loss_tangent: float, - frequency_range: Tuple[float, float], + frequency_range: tuple[float, float], max_num_poles: PositiveInt = DEFAULT_MAX_POLES, number_sampling_frequency: PositiveInt = 10, tolerance_rms: NonNegativeFloat = DEFAULT_TOLERANCE_RMS, + show_progress: bool = True, ) -> PoleResidue: """Fit a constant loss tangent material model. @@ -138,21 +144,27 @@ def constant_loss_tangent_model( Number of sampling frequencies to compute RMS error for fitting. tolerance_rms : float, optional Weighted RMS error below which the fit is successful and the result is returned. + show_progress : bool + Whether to show a progress bar. Returns ------- :class:`.PoleResidue Best results of multiple fits. """ - if number_sampling_frequency < 2: - frequencies = np.array([np.mean(frequency_range)]) - else: - frequencies = np.linspace( - frequency_range[0], frequency_range[1], number_sampling_frequency - ) - wvl_um = C_0 / frequencies - eps_real_array = np.ones_like(frequencies) * eps_real - loss_tangent_array = np.ones_like(frequencies) * loss_tangent - fitter = cls.from_loss_tangent(wvl_um, eps_real_array, loss_tangent_array) - material, _ = fitter.fit(max_num_poles=max_num_poles, tolerance_rms=tolerance_rms) - return material + params, _ = constant_loss_tangent_model( + eps_real=eps_real, + loss_tangent=loss_tangent, + frequency_range=frequency_range, + max_num_poles=max_num_poles, + number_sampling_frequency=number_sampling_frequency, + tolerance_rms=tolerance_rms, + scale_factor=HBAR, + show_progress=show_progress, + ) + + eps_inf, poles, residues = params + + medium = PoleResidue(eps_inf=eps_inf, poles=list(zip(poles, residues))) + + return medium diff --git a/tidy3d/plugins/dispersion/fit_web.py b/tidy3d/plugins/dispersion/fit_web.py index 4eac610734..d8061ddbfd 100644 --- a/tidy3d/plugins/dispersion/fit_web.py +++ b/tidy3d/plugins/dispersion/fit_web.py @@ -1,6 +1,8 @@ """Deprecated module""" -from ...log import log +from __future__ import annotations + +from tidy3d.log import log log.warning( "The module 'plugins.dispersion.fit_web' has been deprecated in favor of " diff --git a/tidy3d/plugins/dispersion/web.py b/tidy3d/plugins/dispersion/web.py index 275ff076e7..186eb0f782 100644 --- a/tidy3d/plugins/dispersion/web.py +++ b/tidy3d/plugins/dispersion/web.py @@ -4,21 +4,21 @@ import ssl from enum import Enum -from typing import Optional, Tuple +from typing import Literal, Optional import pydantic.v1 as pydantic import requests from pydantic.v1 import Field, NonNegativeFloat, PositiveFloat, PositiveInt, validator +from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing +from tidy3d.components.medium import PoleResidue +from tidy3d.components.types import Undefined +from tidy3d.constants import HERTZ, MICROMETER +from tidy3d.exceptions import SetupError, Tidy3dError, WebError +from tidy3d.log import log from tidy3d.web.core.environment import Env from tidy3d.web.core.http_util import get_headers -from ...components.base import Tidy3dBaseModel, skip_if_fields_missing -from ...components.medium import PoleResidue -from ...components.types import Literal -from ...constants import HERTZ, MICROMETER -from ...exceptions import SetupError, Tidy3dError, WebError -from ...log import log from .fit import DispersionFitter BOUND_MAX_FACTOR = 10 @@ -102,8 +102,7 @@ def _validate_lower_frequency_bound(cls, val, values): """bound_f_lower cannot be larger than bound_f.""" if values["bound_f"] is not None and val > values["bound_f"]: raise SetupError( - "The upper bound 'bound_f' cannot be smaller " - "than the lower bound 'bound_f_lower'." + "The upper bound 'bound_f' cannot be smaller than the lower bound 'bound_f_lower'." ) return val @@ -111,18 +110,18 @@ def _validate_lower_frequency_bound(cls, val, values): class FitterData(AdvancedFitterParam): """Data class for request body of Fitter where dipsersion data is input through tuple.""" - wvl_um: Tuple[float, ...] = Field( + wvl_um: tuple[float, ...] = Field( ..., title="Wavelengths", description="A set of wavelengths for dispersion data.", units=MICROMETER, ) - n_data: Tuple[float, ...] = Field( + n_data: tuple[float, ...] = Field( ..., title="Index of refraction", description="Real part of the complex index of refraction at each wavelength.", ) - k_data: Tuple[float, ...] = Field( + k_data: tuple[float, ...] = Field( None, title="Extinction coefficient", description="Imaginary part of the complex index of refraction at each wavelength.", @@ -255,7 +254,7 @@ def _setup_server(url_server: str): return get_headers() - def run(self) -> Tuple[PoleResidue, float]: + def run(self) -> tuple[PoleResidue, float]: """Execute the data fit using the stable fitter in the server. Returns @@ -316,8 +315,8 @@ def run( num_poles: PositiveInt = 1, num_tries: PositiveInt = 50, tolerance_rms: NonNegativeFloat = 1e-2, - advanced_param: AdvancedFitterParam = AdvancedFitterParam(), -) -> Tuple[PoleResidue, float]: + advanced_param: AdvancedFitterParam = Undefined, +) -> tuple[PoleResidue, float]: """Execute the data fit using the stable fitter in the server. Parameters @@ -338,6 +337,8 @@ def run( Tuple[:class:`.PoleResidue`, float] Best results of multiple fits: (dispersive medium, RMS error). """ + if advanced_param is Undefined: + advanced_param = AdvancedFitterParam() task = FitterData.create(fitter, num_poles, num_tries, tolerance_rms, advanced_param) return task.run() @@ -359,7 +360,9 @@ def fit( num_tries: PositiveInt = 50, tolerance_rms: NonNegativeFloat = 1e-2, guess: PoleResidue = None, - advanced_param: AdvancedFitterParam = AdvancedFitterParam(), - ) -> Tuple[PoleResidue, float]: + advanced_param: AdvancedFitterParam = Undefined, + ) -> tuple[PoleResidue, float]: """Deprecated.""" + if advanced_param is Undefined: + advanced_param = AdvancedFitterParam() return run(self, num_poles, num_tries, tolerance_rms, advanced_param) diff --git a/tidy3d/plugins/expressions/__init__.py b/tidy3d/plugins/expressions/__init__.py index 1f8f733f3a..616aac08e8 100644 --- a/tidy3d/plugins/expressions/__init__.py +++ b/tidy3d/plugins/expressions/__init__.py @@ -1,22 +1,24 @@ +from __future__ import annotations + from .base import Expression from .functions import Cos, Exp, Log, Log10, Sin, Sqrt, Tan from .metrics import ModeAmp, ModePower, generate_validation_data from .variables import Constant, Variable __all__ = [ - "Expression", "Constant", - "Variable", - "ModeAmp", - "ModePower", - "generate_validation_data", - "Sin", "Cos", - "Tan", "Exp", + "Expression", "Log", "Log10", + "ModeAmp", + "ModePower", + "Sin", "Sqrt", + "Tan", + "Variable", + "generate_validation_data", ] # The following code dynamically collects all classes that are subclasses of Expression diff --git a/tidy3d/plugins/expressions/base.py b/tidy3d/plugins/expressions/base.py index f24cd57cc3..ff52b648ef 100644 --- a/tidy3d/plugins/expressions/base.py +++ b/tidy3d/plugins/expressions/base.py @@ -1,7 +1,8 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Generator, Optional, Type +from collections.abc import Generator +from typing import TYPE_CHECKING, Any, Optional from tidy3d.components.base import Tidy3dBaseModel from tidy3d.components.types import TYPE_TAG_STR @@ -62,7 +63,7 @@ def parse_obj(cls, obj: dict[str, Any]) -> ExpressionType: return subclass(**obj) def filter( - self, target_type: Type[Expression], target_field: Optional[str] = None + self, target_type: type[Expression], target_field: Optional[str] = None ) -> Generator[Expression, None, None]: """ Find all instances of a given type or field in the expression. @@ -107,12 +108,11 @@ def _find_instances(expr: Expression): def _to_expression(other: NumberOrExpression | dict[str, Any]) -> ExpressionType: if isinstance(other, Expression): return other - elif isinstance(other, dict): + if isinstance(other, dict): return Expression.parse_obj(other) - else: - from .variables import Constant + from .variables import Constant - return Constant(other) + return Constant(other) def __neg__(self) -> Negate: from .operators import Negate diff --git a/tidy3d/plugins/expressions/functions.py b/tidy3d/plugins/expressions/functions.py index 5bcfcf5c1a..e5460fe028 100644 --- a/tidy3d/plugins/expressions/functions.py +++ b/tidy3d/plugins/expressions/functions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any import autograd.numpy as anp diff --git a/tidy3d/plugins/expressions/metrics.py b/tidy3d/plugins/expressions/metrics.py index 04aa79c405..277085bfe7 100644 --- a/tidy3d/plugins/expressions/metrics.py +++ b/tidy3d/plugins/expressions/metrics.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from abc import ABC, abstractmethod from typing import Any, Optional, Union diff --git a/tidy3d/plugins/expressions/types.py b/tidy3d/plugins/expressions/types.py index 861e86353b..1f6a12e9fe 100644 --- a/tidy3d/plugins/expressions/types.py +++ b/tidy3d/plugins/expressions/types.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import TYPE_CHECKING, Annotated, Union from pydantic.v1 import Field diff --git a/tidy3d/plugins/expressions/variables.py b/tidy3d/plugins/expressions/variables.py index ae32591c1e..13cd5534b8 100644 --- a/tidy3d/plugins/expressions/variables.py +++ b/tidy3d/plugins/expressions/variables.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any, Optional import pydantic.v1 as pd @@ -48,12 +50,11 @@ def evaluate(self, *args: Any, **kwargs: Any) -> NumberType: if self.name not in kwargs: raise ValueError(f"Variable '{self.name}' not provided.") return kwargs[self.name] - else: - if not args: - raise ValueError("No positional argument provided for unnamed variable.") - if len(args) > 1: - raise ValueError("Multiple positional arguments provided for unnamed variable.") - return args[0] + if not args: + raise ValueError("No positional argument provided for unnamed variable.") + if len(args) > 1: + raise ValueError("Multiple positional arguments provided for unnamed variable.") + return args[0] def __repr__(self) -> str: return self.name if self.name else "Variable()" diff --git a/tidy3d/plugins/invdes/__init__.py b/tidy3d/plugins/invdes/__init__.py index 8bb3d5e961..86f819248e 100644 --- a/tidy3d/plugins/invdes/__init__.py +++ b/tidy3d/plugins/invdes/__init__.py @@ -1,4 +1,5 @@ # imports from tidy3d.plugins.invdes as tdi +from __future__ import annotations from . import utils from .design import InverseDesign, InverseDesignMulti @@ -14,15 +15,15 @@ from .transformation import FilterProject __all__ = ( + "AdamOptimizer", + "CustomInitializationSpec", + "ErosionDilationPenalty", + "FilterProject", "InverseDesign", "InverseDesignMulti", - "FilterProject", - "ErosionDilationPenalty", - "TopologyDesignRegion", - "AdamOptimizer", "InverseDesignResult", "RandomInitializationSpec", + "TopologyDesignRegion", "UniformInitializationSpec", - "CustomInitializationSpec", "utils", ) diff --git a/tidy3d/plugins/invdes/design.py b/tidy3d/plugins/invdes/design.py index f8a4487b07..42ea65c108 100644 --- a/tidy3d/plugins/invdes/design.py +++ b/tidy3d/plugins/invdes/design.py @@ -62,7 +62,7 @@ def make_objective_fn( direction_multiplier = 1 if maximize else -1 - def objective_fn(params: anp.ndarray, aux_data: dict = None) -> float: + def objective_fn(params: anp.ndarray, aux_data: typing.Optional[dict] = None) -> float: """Full objective function.""" data = self.to_simulation_data(params=params) @@ -124,7 +124,7 @@ class InverseDesign(AbstractInverseDesign): description="Simulation without the design regions or monitors used in the objective fn.", ) - output_monitor_names: typing.Tuple[str, ...] = pd.Field( + output_monitor_names: tuple[str, ...] = pd.Field( None, title="Output Monitor Names", description="Optional names of monitors whose data the differentiable output depends on." @@ -201,7 +201,7 @@ def _validate_metric_data(expr: ExpressionType, simulation: td.Simulation) -> No try: result = expr(data) except Exception as e: - raise ValidationError(f"Failed to evaluate the metric expression: {str(e)}") from e + raise ValidationError(f"Failed to evaluate the metric expression: {e!s}") from e if len(np.ravel(result)) > 1: raise ValidationError( f"The expression must return a scalar value or an array of length 1 (got {result})." @@ -221,10 +221,10 @@ def is_output_monitor(self, monitor: td.Monitor) -> bool: return monitor.name in self.output_monitor_names - def separate_output_monitors(self, monitors: typing.Tuple[td.Monitor]) -> dict: + def separate_output_monitors(self, monitors: tuple[td.Monitor]) -> dict: """Separate monitors into output_monitors and regular monitors.""" - monitor_fields = dict(monitors=[], output_monitors=[]) + monitor_fields = {"monitors": [], "output_monitors": []} for monitor in monitors: key = "output_monitors" if self.is_output_monitor(monitor) else "monitors" @@ -247,7 +247,7 @@ def to_simulation(self, params: anp.ndarray) -> td.Simulation: grid_spec = grid_spec.updated_copy(override_structures=override_structures) return self.simulation.updated_copy( - structures=list(self.simulation.structures) + [design_region_structure], + structures=[*list(self.simulation.structures), design_region_structure], grid_spec=grid_spec, ) @@ -260,13 +260,13 @@ def to_simulation_data(self, params: anp.ndarray, **kwargs) -> td.SimulationData class InverseDesignMulti(AbstractInverseDesign): """``InverseDesign`` with multiple simulations and corresponding postprocess functions.""" - simulations: typing.Tuple[td.Simulation, ...] = pd.Field( + simulations: tuple[td.Simulation, ...] = pd.Field( ..., title="Base Simulations", description="Set of simulation without the design regions or monitors used in the objective fn.", ) - output_monitor_names: typing.Tuple[typing.Union[typing.Tuple[str, ...], None], ...] = pd.Field( + output_monitor_names: tuple[typing.Union[tuple[str, ...], None], ...] = pd.Field( None, title="Output Monitor Names", description="Optional names of monitors whose data the differentiable output depends on." @@ -301,7 +301,7 @@ def task_names(self) -> list[str]: return [f"{self.task_name}_{i}" for i in range(len(self.simulations))] @property - def designs(self) -> typing.List[InverseDesign]: + def designs(self) -> list[InverseDesign]: """List of individual ``InverseDesign`` objects corresponding to this instance.""" designs_list = [] diff --git a/tidy3d/plugins/invdes/initialization.py b/tidy3d/plugins/invdes/initialization.py index eb75a940c4..3acd297d25 100644 --- a/tidy3d/plugins/invdes/initialization.py +++ b/tidy3d/plugins/invdes/initialization.py @@ -21,7 +21,6 @@ class AbstractInitializationSpec(Tidy3dBaseModel, ABC): @abstractmethod def create_parameters(self, shape: tuple[int, ...]) -> NDArray: """Generate the parameter array based on the specification.""" - pass class RandomInitializationSpec(AbstractInitializationSpec): @@ -102,8 +101,7 @@ def _validate_params_dtype(cls, value, values): """Ensure that params is real-valued.""" if np.issubdtype(value.dtype, np.bool_): td.log.warning( - "Got a boolean array for 'params'. " - "This will be treated as a floating point array." + "Got a boolean array for 'params'. This will be treated as a floating point array." ) value = value.astype(float) elif not np.issubdtype(value.dtype, np.floating): diff --git a/tidy3d/plugins/invdes/optimizer.py b/tidy3d/plugins/invdes/optimizer.py index 08758f12b6..a43ba47e23 100644 --- a/tidy3d/plugins/invdes/optimizer.py +++ b/tidy3d/plugins/invdes/optimizer.py @@ -1,4 +1,5 @@ # specification for running the optimizer +from __future__ import annotations import abc import typing @@ -139,7 +140,7 @@ def run( def continue_run( self, result: InverseDesignResult, - num_steps: int = None, + num_steps: typing.Optional[int] = None, post_process_fn: typing.Optional[typing.Callable] = None, callback: typing.Optional[typing.Callable] = None, ) -> InverseDesignResult: @@ -229,7 +230,7 @@ def continue_run( def continue_run_from_file( self, fname: str, - num_steps: int = None, + num_steps: typing.Optional[int] = None, post_process_fn: typing.Optional[typing.Callable] = None, callback: typing.Optional[typing.Callable] = None, ) -> InverseDesignResult: @@ -244,7 +245,7 @@ def continue_run_from_file( def continue_run_from_history( self, - num_steps: int = None, + num_steps: typing.Optional[int] = None, post_process_fn: typing.Optional[typing.Callable] = None, callback: typing.Optional[typing.Callable] = None, ) -> InverseDesignResult: @@ -285,10 +286,10 @@ class AdamOptimizer(AbstractOptimizer): def initial_state(self, parameters: np.ndarray) -> dict: """initial state of the optimizer""" zeros = np.zeros_like(parameters) - return dict(m=zeros, v=zeros, t=0) + return {"m": zeros, "v": zeros, "t": 0} def update( - self, parameters: np.ndarray, gradient: np.ndarray, state: dict = None + self, parameters: np.ndarray, gradient: np.ndarray, state: typing.Optional[dict] = None ) -> tuple[np.ndarray, dict]: if state is None: state = self.initial_state(parameters) @@ -311,5 +312,5 @@ def update( # update parameters and state parameters -= self.learning_rate * m_ / (np.sqrt(v_) + self.eps) - state = dict(m=m, v=v, t=t) + state = {"m": m, "v": v, "t": t} return parameters, state diff --git a/tidy3d/plugins/invdes/penalty.py b/tidy3d/plugins/invdes/penalty.py index 621cbfb9e4..1683f577fd 100644 --- a/tidy3d/plugins/invdes/penalty.py +++ b/tidy3d/plugins/invdes/penalty.py @@ -1,4 +1,5 @@ # define penalties applied to parameters from design region +from __future__ import annotations import abc import typing diff --git a/tidy3d/plugins/invdes/region.py b/tidy3d/plugins/invdes/region.py index b94eaf8682..17fa5009c4 100644 --- a/tidy3d/plugins/invdes/region.py +++ b/tidy3d/plugins/invdes/region.py @@ -1,4 +1,5 @@ # container for specification fully defining the inverse design problem +from __future__ import annotations import abc import typing @@ -38,14 +39,14 @@ class DesignRegion(InvdesBaseModel, abc.ABC): units=td.constants.MICROMETER, ) - eps_bounds: typing.Tuple[float, float] = pd.Field( + eps_bounds: tuple[float, float] = pd.Field( ..., ge=1.0, title="Relative Permittivity Bounds", description="Minimum and maximum relative permittivity expressed to the design region.", ) - transformations: typing.Tuple[TransformationType, ...] = pd.Field( + transformations: tuple[TransformationType, ...] = pd.Field( (), title="Transformations", description="Transformations that get applied from first to last on the parameter array." @@ -55,7 +56,7 @@ class DesignRegion(InvdesBaseModel, abc.ABC): "Specific permittivity values given the density array are determined by ``eps_bounds``.", ) - penalties: typing.Tuple[PenaltyType, ...] = pd.Field( + penalties: tuple[PenaltyType, ...] = pd.Field( (), title="Penalties", description="Set of penalties that get evaluated on the material density. Note that the " @@ -149,7 +150,7 @@ class TopologyDesignRegion(DesignRegion): "is assumed to be uniform, i.e. invariant, in the z direction.", ) - transformations: typing.Tuple[TransformationType, ...] = pd.Field( + transformations: tuple[TransformationType, ...] = pd.Field( (), title="Transformations", description="Transformations that get applied from first to last on the parameter array." @@ -158,7 +159,7 @@ class TopologyDesignRegion(DesignRegion): "permittivity and 1 corresponds to the maximum relative permittivity. " "Specific permittivity values given the density array are determined by ``eps_bounds``.", ) - penalties: typing.Tuple[PenaltyType, ...] = pd.Field( + penalties: tuple[PenaltyType, ...] = pd.Field( (), title="Penalties", description="Set of penalties that get evaluated on the material density. Note that the " @@ -183,7 +184,7 @@ def _validate_eps_values(self): x = self.initial_parameters self.eps_values(x) except Exception as e: - raise ValidationError(f"Could not evaluate transformations: {str(e)}") from e + raise ValidationError(f"Could not evaluate transformations: {e!s}") from e def _validate_penalty_value(self): """Validate the penalty values by evaluating the penalties.""" @@ -191,7 +192,7 @@ def _validate_penalty_value(self): x = self.initial_parameters self.penalty_value(x) except Exception as e: - raise ValidationError(f"Could not evaluate penalties: {str(e)}") from e + raise ValidationError(f"Could not evaluate penalties: {e!s}") from e def _validate_gradients(self): """Validate the gradients of the penalties and transformations.""" @@ -219,7 +220,7 @@ def _validate_gradients(self): "This indicates that the optimization will not function correctly. " "Please double-check the definitions of both the penalties and transformations." ) - elif penalty_independent: + if penalty_independent: td.log.warning( "Penalty gradient seems independent of input, meaning that it " "will not contribute to the objective gradient during optimization. " @@ -244,7 +245,7 @@ def _check_params(params: anp.ndarray = None): ) @property - def params_shape(self) -> typing.Tuple[int, int, int]: + def params_shape(self) -> tuple[int, int, int]: """Shape of the parameters array in (x, y, z), given the ``pixel_size`` and bounds.""" side_lengths = np.array(self.size) num_pixels = np.ceil(side_lengths / self.pixel_size) @@ -289,7 +290,7 @@ def params_ones(self): return self.params_uniform(1.0) @property - def coords(self) -> typing.Dict[str, typing.List[float]]: + def coords(self) -> dict[str, list[float]]: """Coordinates for the custom medium corresponding to this design region.""" lengths = np.array(self.size) @@ -297,7 +298,7 @@ def coords(self) -> typing.Dict[str, typing.List[float]]: rmin, rmax = self.geometry.bounds params_shape = self.params_shape - coords = dict() + coords = {} for dim, ptmin, ptmax, length, num_pts in zip("xyz", rmin, rmax, lengths, params_shape): step_size = length / num_pts if np.isinf(length): diff --git a/tidy3d/plugins/invdes/result.py b/tidy3d/plugins/invdes/result.py index 86e5fcd015..c05aace157 100644 --- a/tidy3d/plugins/invdes/result.py +++ b/tidy3d/plugins/invdes/result.py @@ -1,4 +1,5 @@ # convenient container for the output of the inverse design (specifically the history) +from __future__ import annotations import typing @@ -24,67 +25,67 @@ class InverseDesignResult(InvdesBaseModel): description="Specification describing the inverse design problem we wish to optimize.", ) - params: typing.Tuple[ArrayLike, ...] = pd.Field( + params: tuple[ArrayLike, ...] = pd.Field( (), title="Parameter History", description="History of parameter arrays throughout the optimization.", ) - objective_fn_val: typing.Tuple[float, ...] = pd.Field( + objective_fn_val: tuple[float, ...] = pd.Field( (), title="Objective Function History", description="History of objective function values throughout the optimization.", ) - grad: typing.Tuple[ArrayLike, ...] = pd.Field( + grad: tuple[ArrayLike, ...] = pd.Field( (), title="Gradient History", description="History of objective function gradient arrays throughout the optimization.", ) - penalty: typing.Tuple[float, ...] = pd.Field( + penalty: tuple[float, ...] = pd.Field( (), title="Penalty History", description="History of weighted sum of penalties throughout the optimization.", ) - post_process_val: typing.Tuple[float, ...] = pd.Field( + post_process_val: tuple[float, ...] = pd.Field( (), title="Post-Process Function History", description="History of return values from ``post_process_fn`` throughout the optimization.", ) - simulation: typing.Tuple[td.Simulation, ...] = pd.Field( + simulation: tuple[td.Simulation, ...] = pd.Field( (), title="Simulation History", description="History of ``td.Simulation`` instances throughout the optimization.", ) - opt_state: typing.Tuple[dict, ...] = pd.Field( + opt_state: tuple[dict, ...] = pd.Field( (), title="Optimizer State History", description="History of optimizer states throughout the optimization.", ) @property - def history(self) -> typing.Dict[str, list]: + def history(self) -> dict[str, list]: """The history-containing fields as a dictionary of lists.""" - return dict( - params=list(self.params), - objective_fn_val=list(self.objective_fn_val), - grad=list(self.grad), - penalty=list(self.penalty), - post_process_val=list(self.post_process_val), - opt_state=list(self.opt_state), - ) + return { + "params": list(self.params), + "objective_fn_val": list(self.objective_fn_val), + "grad": list(self.grad), + "penalty": list(self.penalty), + "post_process_val": list(self.post_process_val), + "opt_state": list(self.opt_state), + } @property - def keys(self) -> typing.List[str]: + def keys(self) -> list[str]: """Keys stored in the history.""" return list(self.history.keys()) @property - def last(self) -> typing.Dict[str, typing.Any]: + def last(self) -> dict[str, typing.Any]: """Dictionary of last values in ``self.history``.""" return {key: value[-1] for key, value in self.history.items()} @@ -101,20 +102,20 @@ def get_last(self, key: str) -> typing.Any: """Get the last value from the history.""" return self.get(key=key, index=-1) - def get_sim(self, index: int = -1) -> typing.Union[td.Simulation, typing.List[td.Simulation]]: + def get_sim(self, index: int = -1) -> typing.Union[td.Simulation, list[td.Simulation]]: """Get the simulation at a specific index in the history (list of sims if multi).""" params = np.array(self.get(key="params", index=index)) return self.design.to_simulation(params=params) def get_sim_data( self, index: int = -1, **kwargs - ) -> typing.Union[td.SimulationData, typing.List[td.SimulationData]]: + ) -> typing.Union[td.SimulationData, list[td.SimulationData]]: """Get the simulation data at a specific index in the history (list of simdata if multi).""" params = np.array(self.get(key="params", index=index)) return self.design.to_simulation_data(params=params, **kwargs) @property - def sim_last(self) -> typing.Union[td.Simulation, typing.List[td.Simulation]]: + def sim_last(self) -> typing.Union[td.Simulation, list[td.Simulation]]: """The last simulation.""" return self.get_sim(index=-1) diff --git a/tidy3d/plugins/invdes/transformation.py b/tidy3d/plugins/invdes/transformation.py index cb9e343ceb..c5060209cf 100644 --- a/tidy3d/plugins/invdes/transformation.py +++ b/tidy3d/plugins/invdes/transformation.py @@ -1,4 +1,5 @@ # transformations applied to design region +from __future__ import annotations import abc import typing diff --git a/tidy3d/plugins/invdes/utils.py b/tidy3d/plugins/invdes/utils.py index 3e3e1fd0af..eeb3fff79f 100644 --- a/tidy3d/plugins/invdes/utils.py +++ b/tidy3d/plugins/invdes/utils.py @@ -1,6 +1,7 @@ """Functional utilities that help define postprocessing functions more simply in ``invdes``.""" # TODO: improve these? +from __future__ import annotations import typing diff --git a/tidy3d/plugins/invdes/validators.py b/tidy3d/plugins/invdes/validators.py index cfdaa6ad18..07a522b42e 100644 --- a/tidy3d/plugins/invdes/validators.py +++ b/tidy3d/plugins/invdes/validators.py @@ -1,4 +1,5 @@ # validator utilities for invdes plugin +from __future__ import annotations import typing @@ -23,7 +24,7 @@ def _ignore_field(cls, val): "set this field internally using the design region specifications. " "The supplied value will be ignored. " ) - return None + return return _ignore_field @@ -31,7 +32,9 @@ def _ignore_field(cls, val): def check_pixel_size(sim_field_name: str): """make validator to check the pixel size of sim or list of sims in an ``InverseDesign``.""" - def check_pixel_size_sim(sim: td.Simulation, pixel_size: float, index: int = None) -> None: + def check_pixel_size_sim( + sim: td.Simulation, pixel_size: float, index: typing.Optional[int] = None + ) -> None: """Check a pixel size compared to the simulation min wvl in material.""" if not sim.sources: td.log.warning( diff --git a/tidy3d/plugins/microwave/__init__.py b/tidy3d/plugins/microwave/__init__.py index b0d6f87c8b..bc47c58c21 100644 --- a/tidy3d/plugins/microwave/__init__.py +++ b/tidy3d/plugins/microwave/__init__.py @@ -1,5 +1,7 @@ """Imports from microwave plugin.""" +from __future__ import annotations + from . import models from .array_factor import ( RectangularAntennaArrayCalculator, @@ -21,17 +23,17 @@ __all__ = [ "AxisAlignedPathIntegral", - "CustomPathIntegral2D", - "VoltageIntegralAxisAligned", "CurrentIntegralAxisAligned", - "CustomVoltageIntegral2D", - "CustomCurrentIntegral2D", - "VoltageIntegralTypes", "CurrentIntegralTypes", + "CustomCurrentIntegral2D", + "CustomPathIntegral2D", + "CustomVoltageIntegral2D", "ImpedanceCalculator", + "LobeMeasurer", + "RectangularAntennaArrayCalculator", + "VoltageIntegralAxisAligned", + "VoltageIntegralTypes", "models", "path_integrals_from_lumped_element", "rf_material_library", - "RectangularAntennaArrayCalculator", - "LobeMeasurer", ] diff --git a/tidy3d/plugins/microwave/array_factor.py b/tidy3d/plugins/microwave/array_factor.py index 5becb44414..ca688b7ee5 100644 --- a/tidy3d/plugins/microwave/array_factor.py +++ b/tidy3d/plugins/microwave/array_factor.py @@ -1,28 +1,29 @@ """Convenience functions for estimating antenna radiation by applying array factor.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Optional, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd from pydantic.v1 import NonNegativeFloat, PositiveInt +from tidy3d.components.base import Tidy3dBaseModel, skip_if_fields_missing +from tidy3d.components.data.monitor_data import AbstractFieldProjectionData, DirectivityData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.geometry.base import Box, Geometry +from tidy3d.components.grid.grid_spec import GridSpec, LayerRefinementSpec +from tidy3d.components.lumped_element import LumpedElement +from tidy3d.components.medium import Medium, MediumType3D +from tidy3d.components.monitor import AbstractFieldProjectionMonitor, MonitorType +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.utils import SourceType +from tidy3d.components.structure import MeshOverrideStructure, Structure +from tidy3d.components.types import ArrayLike, Axis, Bound, Undefined +from tidy3d.constants import C_0, inf from tidy3d.log import log -from ...components.base import Tidy3dBaseModel, skip_if_fields_missing -from ...components.data.monitor_data import AbstractFieldProjectionData, DirectivityData -from ...components.data.sim_data import SimulationData -from ...components.geometry.base import Box, Geometry -from ...components.grid.grid_spec import GridSpec, LayerRefinementSpec -from ...components.lumped_element import LumpedElement -from ...components.medium import Medium, MediumType3D -from ...components.monitor import AbstractFieldProjectionMonitor, MonitorType -from ...components.simulation import Simulation -from ...components.source.utils import SourceType -from ...components.structure import MeshOverrideStructure, Structure -from ...components.types import ArrayLike, Axis, Bound -from ...constants import C_0, inf - class AbstractAntennaArrayCalculator(Tidy3dBaseModel, ABC): """Abstract base for phased array calculators.""" @@ -159,7 +160,7 @@ def _try_to_expand_geometry( def _duplicate_or_expand_list_of_objects( self, - objects: Tuple[ + objects: tuple[ Union[Structure, MeshOverrideStructure, LayerRefinementSpec, LumpedElement], ... ], old_sim_bounds: Bound, @@ -228,7 +229,7 @@ def _duplicate_or_expand_list_of_objects( def _expand_monitors( self, - monitors: Tuple[MonitorType, ...], + monitors: tuple[MonitorType, ...], antenna_bounds: Bound, new_sim_bounds: Bound, old_sim_bounds: Bound, @@ -300,7 +301,7 @@ def _expand_monitors( return array_monitors def _duplicate_structures( - self, structures: Tuple[Structure, ...], new_sim_bounds: Bound, old_sim_bounds: Bound + self, structures: tuple[Structure, ...], new_sim_bounds: Bound, old_sim_bounds: Bound ): """Duplicate structures.""" @@ -310,8 +311,8 @@ def _duplicate_structures( def _duplicate_sources( self, - sources: Tuple[SourceType, ...], - lumped_elements: Tuple[LumpedElement, ...], + sources: tuple[SourceType, ...], + lumped_elements: tuple[LumpedElement, ...], old_sim_bounds: Bound, new_sim_bounds: Bound, ): @@ -619,23 +620,23 @@ class RectangularAntennaArrayCalculator(AbstractAntennaArrayCalculator): ... ) # doctest: +SKIP """ - array_size: Tuple[PositiveInt, PositiveInt, PositiveInt] = pd.Field( + array_size: tuple[PositiveInt, PositiveInt, PositiveInt] = pd.Field( title="Array Size", description="Number of antennas along x, y, and z directions.", ) - spacings: Tuple[NonNegativeFloat, NonNegativeFloat, NonNegativeFloat] = pd.Field( + spacings: tuple[NonNegativeFloat, NonNegativeFloat, NonNegativeFloat] = pd.Field( title="Antenna Spacings", description="Center-to-center spacings between antennas along x, y, and z directions.", ) - phase_shifts: Tuple[float, float, float] = pd.Field( + phase_shifts: tuple[float, float, float] = pd.Field( (0, 0, 0), title="Phase Shifts", description="Phase-shifts between antennas along x, y, and z directions.", ) - amp_multipliers: Tuple[Optional[ArrayLike], Optional[ArrayLike], Optional[ArrayLike]] = ( + amp_multipliers: tuple[Optional[ArrayLike], Optional[ArrayLike], Optional[ArrayLike]] = ( pd.Field( (None, None, None), title="Amplitude Multipliers", @@ -702,7 +703,7 @@ def _antenna_phases(self) -> ArrayLike: return np.ravel(sum(p for p in phase_shifts_grid)) @property - def _extend_dims(self) -> Tuple[Axis, ...]: + def _extend_dims(self) -> tuple[Axis, ...]: """Dimensions along which antennas will be duplicated.""" return [ind for ind, size in enumerate(self.array_size) if size > 1] @@ -711,7 +712,7 @@ def array_factor( theta: Union[float, ArrayLike], phi: Union[float, ArrayLike], frequency: Union[NonNegativeFloat, ArrayLike], - medium: MediumType3D = Medium(), + medium: MediumType3D = Undefined, ) -> ArrayLike: """ Compute the array factor for a 3D antenna array. @@ -730,6 +731,8 @@ def array_factor( ArrayLike Array factor values for each combination of theta and phi. """ + if medium is Undefined: + medium = Medium() # Convert all inputs to numpy arrays theta_array = np.atleast_1d(theta) diff --git a/tidy3d/plugins/microwave/auto_path_integrals.py b/tidy3d/plugins/microwave/auto_path_integrals.py index d9140b7a57..b93e611f77 100644 --- a/tidy3d/plugins/microwave/auto_path_integrals.py +++ b/tidy3d/plugins/microwave/auto_path_integrals.py @@ -1,10 +1,18 @@ """Helpers for automatic setup of path integrals.""" -from ...components.geometry.base import Box -from ...components.geometry.utils import SnapBehavior, SnapLocation, SnappingSpec, snap_box_to_grid -from ...components.grid.grid import Grid -from ...components.lumped_element import LinearLumpedElement -from ...components.types import Direction +from __future__ import annotations + +from tidy3d.components.geometry.base import Box +from tidy3d.components.geometry.utils import ( + SnapBehavior, + SnapLocation, + SnappingSpec, + snap_box_to_grid, +) +from tidy3d.components.grid.grid import Grid +from tidy3d.components.lumped_element import LinearLumpedElement +from tidy3d.components.types import Direction + from .path_integrals import ( CurrentIntegralAxisAligned, VoltageIntegralAxisAligned, diff --git a/tidy3d/plugins/microwave/custom_path_integrals.py b/tidy3d/plugins/microwave/custom_path_integrals.py index 6b6c48469a..d1e2c89a19 100644 --- a/tidy3d/plugins/microwave/custom_path_integrals.py +++ b/tidy3d/plugins/microwave/custom_path_integrals.py @@ -2,19 +2,20 @@ from __future__ import annotations -from typing import Literal +from typing import Literal, Optional import numpy as np import pydantic.v1 as pd import shapely import xarray as xr -from ...components.base import cached_property -from ...components.geometry.base import Geometry -from ...components.types import ArrayFloat2D, Ax, Axis, Bound, Coordinate, Direction -from ...components.viz import add_ax_if_none -from ...constants import MICROMETER, fp_eps -from ...exceptions import SetupError +from tidy3d.components.base import cached_property +from tidy3d.components.geometry.base import Geometry +from tidy3d.components.types import ArrayFloat2D, Ax, Axis, Bound, Coordinate, Direction +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import MICROMETER, fp_eps +from tidy3d.exceptions import SetupError + from .path_integrals import ( AbstractAxesRH, AxisAlignedPathIntegral, @@ -263,9 +264,9 @@ def compute_voltage(self, em_field: MonitorDataTypes) -> IntegralResultTypes: @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **path_kwargs, ) -> Ax: @@ -336,9 +337,9 @@ def compute_current(self, em_field: MonitorDataTypes) -> IntegralResultTypes: @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **path_kwargs, ) -> Ax: @@ -393,5 +394,4 @@ def sign(self) -> Direction: is_ccw = not is_ccw if is_ccw: return "+" - else: - return "-" + return "-" diff --git a/tidy3d/plugins/microwave/impedance_calculator.py b/tidy3d/plugins/microwave/impedance_calculator.py index 488fbcd9b1..a400818620 100644 --- a/tidy3d/plugins/microwave/impedance_calculator.py +++ b/tidy3d/plugins/microwave/impedance_calculator.py @@ -7,11 +7,14 @@ import numpy as np import pydantic.v1 as pd -from ...components.base import Tidy3dBaseModel -from ...components.data.monitor_data import FieldTimeData -from ...constants import OHM -from ...exceptions import ValidationError -from ...log import log +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.data.data_array import FreqDataArray, FreqModeDataArray, TimeDataArray +from tidy3d.components.data.monitor_data import FieldTimeData +from tidy3d.components.monitor import ModeMonitor, ModeSolverMonitor +from tidy3d.constants import OHM +from tidy3d.exceptions import ValidationError +from tidy3d.log import log + from .custom_path_integrals import CustomCurrentIntegral2D, CustomVoltageIntegral2D from .path_integrals import ( AxisAlignedPathIntegral, @@ -59,9 +62,9 @@ def compute_impedance(self, em_field: MonitorDataTypes) -> IntegralResultTypes: AxisAlignedPathIntegral._check_monitor_data_supported(em_field=em_field) # If both voltage and current integrals have been defined then impedance is computed directly - if self.voltage_integral: + if self.voltage_integral is not None: voltage = self.voltage_integral.compute_voltage(em_field) - if self.current_integral: + if self.current_integral is not None: current = self.current_integral.compute_current(em_field) # If only one of the integrals has been provided, then the computation falls back to using @@ -70,20 +73,31 @@ def compute_impedance(self, em_field: MonitorDataTypes) -> IntegralResultTypes: # a time signal, then it is real and flux corresponds to the instantaneous power. Otherwise # the input field is in frequency domain, where flux indicates the time-averaged power # 0.5*Re(V*conj(I)). - if not self.voltage_integral: - flux = em_field.flux + # We explicitly take the real part, in case Bloch BCs were used in the simulation. + flux_sign = 1.0 + # Determine flux sign + if isinstance(em_field.monitor, ModeSolverMonitor): + flux_sign = 1 if em_field.monitor.direction == "+" else -1 + if isinstance(em_field.monitor, ModeMonitor): + flux_sign = 1 if em_field.monitor.store_fields_direction == "+" else -1 + + if self.voltage_integral is None: + flux = flux_sign * em_field.complex_flux if isinstance(em_field, FieldTimeData): - voltage = flux.abs / current + impedance = flux / np.real(current) ** 2 else: - voltage = 2 * flux.abs / np.conj(current) - if not self.current_integral: - flux = em_field.flux + impedance = 2 * flux / (current * np.conj(current)) + elif self.current_integral is None: + flux = flux_sign * em_field.complex_flux if isinstance(em_field, FieldTimeData): - current = flux.abs / voltage + impedance = np.real(voltage) ** 2 / flux else: - current = np.conj(2 * flux.abs / voltage) - - impedance = voltage / current + impedance = (voltage * np.conj(voltage)) / (2 * np.conj(flux)) + else: + if isinstance(em_field, FieldTimeData): + impedance = np.real(voltage) / np.real(current) + else: + impedance = voltage / current impedance = ImpedanceCalculator._set_data_array_attributes(impedance) return impedance @@ -100,6 +114,13 @@ def check_voltage_or_current(cls, val, values): @staticmethod def _set_data_array_attributes(data_array: IntegralResultTypes) -> IntegralResultTypes: """Helper to set additional metadata for ``IntegralResultTypes``.""" + # Determine type based on coords present + if "mode_index" in data_array.coords: + data_array = FreqModeDataArray(data_array) + elif "f" in data_array.coords: + data_array = FreqDataArray(data_array) + else: + data_array = TimeDataArray(data_array) data_array.name = "Z0" return data_array.assign_attrs(units=OHM, long_name="characteristic impedance") diff --git a/tidy3d/plugins/microwave/lobe_measurer.py b/tidy3d/plugins/microwave/lobe_measurer.py index 9bf0f61ddc..c843314a8f 100644 --- a/tidy3d/plugins/microwave/lobe_measurer.py +++ b/tidy3d/plugins/microwave/lobe_measurer.py @@ -1,18 +1,20 @@ """Tool for finding and characterizing lobes in antenna radiation patterns.""" +from __future__ import annotations + from math import isclose, isnan from typing import Optional import numpy as np import pydantic.v1 as pd from pandas import DataFrame -from scipy.signal import find_peaks, peak_widths -from ...components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ...components.types import ArrayFloat1D, ArrayLike, Ax -from ...constants import fp_eps -from ...exceptions import ValidationError -from ...log import log +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.types import ArrayFloat1D, ArrayLike, Ax +from tidy3d.constants import fp_eps +from tidy3d.exceptions import ValidationError +from tidy3d.log import log + from .viz import plot_params_lobe_FNBW, plot_params_lobe_peak, plot_params_lobe_width # The minimum plateau size for peak finding, which is set to 0 to ensure that all peaks are found. @@ -129,6 +131,8 @@ def lobe_measures(self) -> DataFrame: DataFrame A DataFrame containing all lobe measures, where rows indicate the lobe index. """ + from scipy.signal import find_peaks + if self.apply_cyclic_extension: angle, signal = self.cyclic_extension(self.angle, self.radiation_pattern) else: @@ -228,6 +232,8 @@ def _calc_peak_widths( self, angle: ArrayLike, signal: ArrayLike, peaks: ArrayLike ) -> tuple[ArrayLike, ArrayLike, ArrayLike, ArrayLike]: """Get the peak widths in terms of the angular coordinates.""" + from scipy.signal import peak_widths + rel_height = 1.0 - self.width_measure last_element = len(signal) - 1 left_ips = np.zeros_like(peaks) diff --git a/tidy3d/plugins/microwave/models/__init__.py b/tidy3d/plugins/microwave/models/__init__.py index 458fed0c15..211c81c8f3 100644 --- a/tidy3d/plugins/microwave/models/__init__.py +++ b/tidy3d/plugins/microwave/models/__init__.py @@ -1,8 +1,10 @@ """Imports for transmission line models.""" +from __future__ import annotations + from . import coupled_microstrip, microstrip __all__ = [ - microstrip, - coupled_microstrip, + "coupled_microstrip", + "microstrip", ] diff --git a/tidy3d/plugins/microwave/models/coupled_microstrip.py b/tidy3d/plugins/microwave/models/coupled_microstrip.py index 85de223cfd..a6dd4d1c11 100644 --- a/tidy3d/plugins/microwave/models/coupled_microstrip.py +++ b/tidy3d/plugins/microwave/models/coupled_microstrip.py @@ -7,6 +7,8 @@ Transactions on Microwave Theory and Techniques, 32(1), 83-90. """ +from __future__ import annotations + import numpy as np from . import microstrip diff --git a/tidy3d/plugins/microwave/models/microstrip.py b/tidy3d/plugins/microwave/models/microstrip.py index aad29fd7d6..6545be1852 100644 --- a/tidy3d/plugins/microwave/models/microstrip.py +++ b/tidy3d/plugins/microwave/models/microstrip.py @@ -11,9 +11,11 @@ for open end effect of microstrip lines.” Electronics Letters 17 (1981): 123-125. """ +from __future__ import annotations + import numpy as np -from ....constants import ETA_0 +from tidy3d.constants import ETA_0 def _f(normalized_width: float) -> float: diff --git a/tidy3d/plugins/microwave/path_integrals.py b/tidy3d/plugins/microwave/path_integrals.py index 8b06cb2334..802f5b0d92 100644 --- a/tidy3d/plugins/microwave/path_integrals.py +++ b/tidy3d/plugins/microwave/path_integrals.py @@ -3,15 +3,14 @@ from __future__ import annotations from abc import ABC, abstractmethod -from typing import Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd -import shapely as shapely import xarray as xr -from ...components.base import Tidy3dBaseModel, cached_property -from ...components.data.data_array import ( +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.data.data_array import ( FreqDataArray, FreqModeDataArray, ScalarFieldDataArray, @@ -19,14 +18,15 @@ ScalarModeFieldDataArray, TimeDataArray, ) -from ...components.data.monitor_data import FieldData, FieldTimeData, ModeData, ModeSolverData -from ...components.geometry.base import Box, Geometry -from ...components.types import Ax, Axis, Coordinate2D, Direction -from ...components.validators import assert_line, assert_plane -from ...components.viz import add_ax_if_none -from ...constants import AMP, VOLT, fp_eps -from ...exceptions import DataError, Tidy3dError -from ...log import log +from tidy3d.components.data.monitor_data import FieldData, FieldTimeData, ModeData, ModeSolverData +from tidy3d.components.geometry.base import Box, Geometry +from tidy3d.components.types import Ax, Axis, Coordinate2D, Direction +from tidy3d.components.validators import assert_line, assert_plane +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import AMP, VOLT, fp_eps +from tidy3d.exceptions import DataError, Tidy3dError +from tidy3d.log import log + from .viz import ( ARROW_CURRENT, plot_params_current_path, @@ -57,8 +57,7 @@ def remaining_axes(self) -> tuple[Axis, Axis]: axes.pop(self.main_axis) if self.main_axis == 1: return (axes[1], axes[0]) - else: - return (axes[0], axes[1]) + return (axes[0], axes[1]) @cached_property def remaining_dims(self) -> tuple[str, str]: @@ -105,7 +104,7 @@ class AxisAlignedPathIntegral(AbstractAxesRH, Box): def compute_integral(self, scalar_field: EMScalarFieldType) -> IntegralResultTypes: """Computes the defined integral given the input ``scalar_field``.""" - if not scalar_field.does_cover(self.bounds): + if not scalar_field.does_cover(self.bounds, fp_eps, np.finfo(np.float32).smallest_normal): raise DataError("Scalar field does not cover the integration domain.") coord = "xyz"[self.main_axis] @@ -211,10 +210,9 @@ def _make_result_data_array(result: xr.DataArray) -> IntegralResultTypes: """Helper for creating the proper result type.""" if "t" in result.coords: return TimeDataArray(data=result.data, coords=result.coords) - elif "f" in result.coords and "mode_index" in result.coords: + if "f" in result.coords and "mode_index" in result.coords: return FreqModeDataArray(data=result.data, coords=result.coords) - else: - return FreqDataArray(data=result.data, coords=result.coords) + return FreqDataArray(data=result.data, coords=result.coords) class VoltageIntegralAxisAligned(AxisAlignedPathIntegral): @@ -254,9 +252,9 @@ def _set_data_array_attributes(data_array: IntegralResultTypes) -> IntegralResul def from_terminal_positions( plus_terminal: float, minus_terminal: float, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, extrapolate_to_endpoints: bool = True, snap_path_to_grid: bool = True, ) -> VoltageIntegralAxisAligned: @@ -310,9 +308,9 @@ def from_terminal_positions( @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **path_kwargs, ) -> Ax: @@ -509,9 +507,9 @@ def _set_data_array_attributes(data_array: IntegralResultTypes) -> IntegralResul @add_ax_if_none def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **path_kwargs, ) -> Ax: diff --git a/tidy3d/plugins/microwave/rf_material_library.py b/tidy3d/plugins/microwave/rf_material_library.py index 690333bce1..7cb784dd87 100644 --- a/tidy3d/plugins/microwave/rf_material_library.py +++ b/tidy3d/plugins/microwave/rf_material_library.py @@ -1,8 +1,11 @@ """Holds dispersive models for several commonly used RF materials.""" # from ...components.base import Tidy3dBaseModel -from ...components.medium import PoleResidue -from ...material_library.material_library import MaterialItem, VariantItem +from __future__ import annotations + +from tidy3d.components.medium import PoleResidue +from tidy3d.material_library.material_library import MaterialItem, VariantItem + from .rf_material_reference import rf_material_refs Rogers3003_design = VariantItem( @@ -201,53 +204,53 @@ reference=[rf_material_refs["FR4_lowloss"]], ) -rf_material_library = dict( - RO3003=MaterialItem( +rf_material_library = { + "RO3003": MaterialItem( name="Rogers3003", - variants=dict( - design=Rogers3003_design, - process=Rogers3003_process, - ), + variants={ + "design": Rogers3003_design, + "process": Rogers3003_process, + }, default="design", ), - RO3010=MaterialItem( + "RO3010": MaterialItem( name="Rogers3010", - variants=dict( - design=Rogers3010_design, - process=Rogers3010_process, - ), + variants={ + "design": Rogers3010_design, + "process": Rogers3010_process, + }, default="design", ), - RO4003C=MaterialItem( + "RO4003C": MaterialItem( name="Rogers4003C", - variants=dict( - design=Rogers4003C_design, - process=Rogers4003C_process, - ), + variants={ + "design": Rogers4003C_design, + "process": Rogers4003C_process, + }, default="design", ), - RO4350B=MaterialItem( + "RO4350B": MaterialItem( name="Rogers4350B", - variants=dict( - design=Rogers4350B_design, - process=Rogers4350B_process, - ), + variants={ + "design": Rogers4350B_design, + "process": Rogers4350B_process, + }, default="design", ), - AD255C=MaterialItem( + "AD255C": MaterialItem( name="ArlonAD255C", - variants=dict( - design=ArlonAD255C_design, - process=ArlonAD255C_process, - ), + variants={ + "design": ArlonAD255C_design, + "process": ArlonAD255C_process, + }, default="design", ), - FR4=MaterialItem( + "FR4": MaterialItem( name="FR4", - variants=dict( - standard=FR4_standard, - lowloss=FR4_lowloss, - ), + variants={ + "standard": FR4_standard, + "lowloss": FR4_lowloss, + }, default="standard", ), -) +} diff --git a/tidy3d/plugins/microwave/rf_material_reference.py b/tidy3d/plugins/microwave/rf_material_reference.py index 0767687dda..895fb6e91b 100644 --- a/tidy3d/plugins/microwave/rf_material_reference.py +++ b/tidy3d/plugins/microwave/rf_material_reference.py @@ -1,41 +1,43 @@ """Holds the reference materials for Tidy3D material library.""" -from ...material_library.material_reference import ReferenceData +from __future__ import annotations -rf_material_refs = dict( - Rogers3003=ReferenceData( +from tidy3d.material_library.material_reference import ReferenceData + +rf_material_refs = { + "Rogers3003": ReferenceData( manufacturer="Rogers Corporation", datasheet_title="RO3003™ Laminates", url="https://www.rogerscorp.com/advanced-electronics-solutions/ro3000-series-laminates/ro3003-laminates", ), - Rogers3010=ReferenceData( + "Rogers3010": ReferenceData( manufacturer="Rogers Corporation", datasheet_title="RO3010™ Laminates", url="https://www.rogerscorp.com/advanced-electronics-solutions/ro3000-series-laminates/ro3010-laminates", ), - Rogers4003C=ReferenceData( + "Rogers4003C": ReferenceData( manufacturer="Rogers Corporation", datasheet_title="RO4003C™ Laminates", url="https://www.rogerscorp.com/advanced-electronics-solutions/ro4000-series-laminates/ro4350b-laminates", ), - Rogers4350B=ReferenceData( + "Rogers4350B": ReferenceData( manufacturer="Rogers Corporation", datasheet_title="RO4350B™ Laminates", url="https://www.rogerscorp.com/advanced-electronics-solutions/ro4000-series-laminates/ro4350b-laminates", ), - ArlonAD255C=ReferenceData( + "ArlonAD255C": ReferenceData( manufacturer="Rogers Corporation", datasheet_title="AD255C High Performance Polyimide Laminates", url="https://www.rogerscorp.com/advanced-electronics-solutions/ad-series-laminates/ad255c-laminates", ), - FR4_standard=ReferenceData( + "FR4_standard": ReferenceData( manufacturer="Isola", datasheet_title="Standard FR-4 Epoxy Glass Cloth Laminate", url="https://www.isola-group.com/pcb-laminates-prepreg/is410-fr-4-epoxy-laminate-and-prepreg/", ), - FR4_lowloss=ReferenceData( + "FR4_lowloss": ReferenceData( manufacturer="Isola", datasheet_title="Low loss FR-4 Epoxy Glass Cloth Laminate", url="https://www.isola-group.com/pcb-laminates-prepreg/is410-fr-4-epoxy-laminate-and-prepreg/", ), -) +} diff --git a/tidy3d/plugins/microwave/viz.py b/tidy3d/plugins/microwave/viz.py index 5a8b3dd582..72f4570c86 100644 --- a/tidy3d/plugins/microwave/viz.py +++ b/tidy3d/plugins/microwave/viz.py @@ -1,8 +1,10 @@ """Utilities for plotting microwave components""" +from __future__ import annotations + from numpy import inf -from ...components.viz import PathPlotParams +from tidy3d.components.viz import PathPlotParams """ Constants """ VOLTAGE_COLOR = "red" @@ -11,13 +13,13 @@ LOBE_WIDTH_COLOR = "tab:orange" LOBE_FNBW_COLOR = "tab:blue" PATH_LINEWIDTH = 2 -ARROW_CURRENT = dict( - arrowstyle="-|>", - mutation_scale=32, - linestyle="", - lw=PATH_LINEWIDTH, - color=CURRENT_COLOR, -) +ARROW_CURRENT = { + "arrowstyle": "-|>", + "mutation_scale": 32, + "linestyle": "", + "lw": PATH_LINEWIDTH, + "color": CURRENT_COLOR, +} plot_params_voltage_path = PathPlotParams( alpha=1.0, diff --git a/tidy3d/plugins/mode/__init__.py b/tidy3d/plugins/mode/__init__.py index 3a37ced052..6cff69cefc 100644 --- a/tidy3d/plugins/mode/__init__.py +++ b/tidy3d/plugins/mode/__init__.py @@ -1,5 +1,7 @@ """Imports from mode solver plugin.""" +from __future__ import annotations + from .mode_solver import ModeSolver, ModeSolverData __all__ = ["ModeSolver", "ModeSolverData"] diff --git a/tidy3d/plugins/mode/mode_solver.py b/tidy3d/plugins/mode/mode_solver.py index 12716b0daf..691ca88e45 100644 --- a/tidy3d/plugins/mode/mode_solver.py +++ b/tidy3d/plugins/mode/mode_solver.py @@ -4,8 +4,8 @@ from __future__ import annotations -from ...components.data.monitor_data import ModeSolverData -from ...components.mode.mode_solver import MODE_MONITOR_NAME, MODE_PLANE_TYPE, ModeSolver +from tidy3d.components.data.monitor_data import ModeSolverData +from tidy3d.components.mode.mode_solver import MODE_MONITOR_NAME, MODE_PLANE_TYPE, ModeSolver _ = ModeSolver _ = ModeSolverData diff --git a/tidy3d/plugins/mode/web.py b/tidy3d/plugins/mode/web.py index edbbbeccac..c6ddf19f4a 100644 --- a/tidy3d/plugins/mode/web.py +++ b/tidy3d/plugins/mode/web.py @@ -1,5 +1,7 @@ """Web API for mode solver""" -from ...web.api.mode import run, run_batch +from __future__ import annotations + +from tidy3d.web.api.mode import run, run_batch __all__ = ["run", "run_batch"] diff --git a/tidy3d/plugins/polyslab/__init__.py b/tidy3d/plugins/polyslab/__init__.py index 0f89f97513..31f4fbce4f 100644 --- a/tidy3d/plugins/polyslab/__init__.py +++ b/tidy3d/plugins/polyslab/__init__.py @@ -1,5 +1,7 @@ """Imports from complex polyslab plugin.""" +from __future__ import annotations + from .polyslab import ComplexPolySlab __all__ = ["ComplexPolySlab"] diff --git a/tidy3d/plugins/polyslab/polyslab.py b/tidy3d/plugins/polyslab/polyslab.py index 1fb496bd09..a5dfa3cefd 100644 --- a/tidy3d/plugins/polyslab/polyslab.py +++ b/tidy3d/plugins/polyslab/polyslab.py @@ -1,8 +1,10 @@ """Divide a complex polyslab where self-intersecting polygon can occur during extrusion.""" -from ...components.geometry.polyslab import ComplexPolySlabBase -from ...components.medium import MediumType -from ...components.structure import Structure +from __future__ import annotations + +from tidy3d.components.geometry.polyslab import ComplexPolySlabBase +from tidy3d.components.medium import MediumType +from tidy3d.components.structure import Structure class ComplexPolySlab(ComplexPolySlabBase): diff --git a/tidy3d/plugins/pytorch/__init__.py b/tidy3d/plugins/pytorch/__init__.py index e3bf690e24..8ea92eb9ec 100644 --- a/tidy3d/plugins/pytorch/__init__.py +++ b/tidy3d/plugins/pytorch/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from .wrapper import to_torch __all__ = ["to_torch"] diff --git a/tidy3d/plugins/pytorch/wrapper.py b/tidy3d/plugins/pytorch/wrapper.py index ffdabf0bd1..e5d0597337 100644 --- a/tidy3d/plugins/pytorch/wrapper.py +++ b/tidy3d/plugins/pytorch/wrapper.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import inspect import torch from autograd import make_vjp -from autograd.extend import vspace def to_torch(fun): @@ -77,10 +78,11 @@ def forward(ctx, *args): @staticmethod def backward(ctx, grad_output): - _grads = ctx.vjp(vspace(grad_output.detach().cpu().numpy()).ones()) + numpy_grad_output = grad_output.detach().cpu().numpy() + _grads = ctx.vjp(numpy_grad_output) grads = [None] * ctx.num_args for idx, grad in zip(ctx.grad_argnums, _grads): - grads[idx] = torch.as_tensor(grad, device=ctx.device) * grad_output + grads[idx] = torch.as_tensor(grad, device=ctx.device) return tuple(grads) def apply(*args, **kwargs): diff --git a/tidy3d/plugins/resonance/__init__.py b/tidy3d/plugins/resonance/__init__.py index 2da284f233..9fa193fffc 100644 --- a/tidy3d/plugins/resonance/__init__.py +++ b/tidy3d/plugins/resonance/__init__.py @@ -1,5 +1,7 @@ """Imports from resonance fitter plugin.""" +from __future__ import annotations + from .resonance import ResonanceFinder __all__ = ["ResonanceFinder"] diff --git a/tidy3d/plugins/resonance/resonance.py b/tidy3d/plugins/resonance/resonance.py index 924a24e409..0f49c0f0c9 100644 --- a/tidy3d/plugins/resonance/resonance.py +++ b/tidy3d/plugins/resonance/resonance.py @@ -1,20 +1,21 @@ """Find resonances in time series data""" +from __future__ import annotations + from functools import partial -from typing import List, Tuple, Union +from typing import Union import numpy as np -import scipy.linalg import xarray as xr from pydantic.v1 import Field, NonNegativeFloat, PositiveInt, validator -from ...components.base import Tidy3dBaseModel -from ...components.data.data_array import ScalarFieldTimeDataArray -from ...components.data.monitor_data import FieldTimeData -from ...components.types import ArrayComplex1D, ArrayComplex2D, ArrayComplex3D, ArrayFloat1D -from ...constants import HERTZ -from ...exceptions import SetupError, ValidationError -from ...log import log +from tidy3d.components.base import Tidy3dBaseModel +from tidy3d.components.data.data_array import ScalarFieldTimeDataArray +from tidy3d.components.data.monitor_data import FieldTimeData +from tidy3d.components.types import ArrayComplex1D, ArrayComplex2D, ArrayComplex3D, ArrayFloat1D +from tidy3d.constants import HERTZ +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.log import log INIT_NUM_FREQS = 200 @@ -69,7 +70,7 @@ class ResonanceFinder(Tidy3dBaseModel): ... # A given dataframe """ - freq_window: Tuple[float, float] = Field( + freq_window: tuple[float, float] = Field( ..., title="Window ``[fmin, fmax]``", description="Window ``[fmin, fmax]`` for the initial frequencies. " @@ -110,7 +111,7 @@ def _check_freq_window(cls, val): ) return val - def run(self, signals: Union[FieldTimeData, Tuple[FieldTimeData, ...]]) -> xr.Dataset: + def run(self, signals: Union[FieldTimeData, tuple[FieldTimeData, ...]]) -> xr.Dataset: """Finds resonances in a :class:`.FieldTimeData` or a Tuple of such. The time coordinates must be uniformly spaced, and the spacing must be the same across all supplied data. The resonance finder runs on the sum of the @@ -158,7 +159,7 @@ def run_scalar_field_time(self, signal: ScalarFieldTimeDataArray) -> xr.Dataset: signal, dt = self._validate_scalar_field_time(signal) return self.run_raw_signal(signal, dt) - def run_raw_signal(self, signal: List[complex], time_step: float) -> xr.Dataset: + def run_raw_signal(self, signal: list[complex], time_step: float) -> xr.Dataset: """Finds resonances in a time series. Note that the signal should start after the sources have turned off. @@ -207,7 +208,7 @@ def run_raw_signal(self, signal: List[complex], time_step: float) -> xr.Dataset: def _validate_scalar_field_time( self, signal: ScalarFieldTimeDataArray - ) -> Tuple[ArrayComplex1D, float]: + ) -> tuple[ArrayComplex1D, float]: """Validates a :class:`.ScalarFieldTimeDataArray` and returns the time step as well as underlying data array.""" dts = np.diff(signal.t) @@ -227,12 +228,12 @@ def _validate_scalar_field_time( return np.squeeze(signal.data), dt def _aggregate_field_time_comps( - self, signals: Tuple[FieldTimeData, ...], comps + self, signals: tuple[FieldTimeData, ...], comps ) -> ScalarFieldTimeDataArray: """Aggregates the given components from several :class:`.FieldTimeData`.""" total_signal = None dt = -1 - coords = dict(x=[0], y=[0], z=[0], t=[0]) + coords = {"x": [0], "y": [0], "z": [0], "t": [0]} for sig_field in signals: for comp in comps: @@ -261,7 +262,7 @@ def _aggregate_field_time_comps( ) def _aggregate_field_time( - self, signals: Union[FieldTimeData, Tuple[FieldTimeData, ...]] + self, signals: Union[FieldTimeData, tuple[FieldTimeData, ...]] ) -> ScalarFieldTimeDataArray: """Aggregates several :class:`.FieldTimeData` into a single :class:`.ScalarFieldTimeDataArray`.""" @@ -345,7 +346,7 @@ def _gram_schmidt(self, a_matrix: ArrayComplex2D) -> ArrayComplex2D: def _solve_gen_eig_prob( self, a_matrix: ArrayComplex2D, b_matrix: ArrayComplex2D, rcond: float - ) -> Tuple[ArrayComplex1D, ArrayComplex2D]: + ) -> tuple[ArrayComplex1D, ArrayComplex2D]: """Solve a generalized eigenvalue problem of the form .. math:: @@ -359,6 +360,8 @@ def _solve_gen_eig_prob( I. Theory and application to a quantum-dynamics model," J. Chem. Phys. 102, 8001 (1995). """ + import scipy.linalg + eigvals_b, eigvecs_b = scipy.linalg.eig(b_matrix) large_inds = np.abs(eigvals_b) > rcond * np.amax(np.abs(eigvals_b)) eigvals_b = eigvals_b[large_inds] diff --git a/tidy3d/plugins/smatrix/__init__.py b/tidy3d/plugins/smatrix/__init__.py index 8152d0d748..73591039a7 100644 --- a/tidy3d/plugins/smatrix/__init__.py +++ b/tidy3d/plugins/smatrix/__init__.py @@ -1,5 +1,7 @@ """Imports from scattering matrix plugin.""" +from __future__ import annotations + import warnings from .component_modelers.modal import AbstractComponentModeler, ComponentModeler, ModalPortDataArray @@ -20,13 +22,13 @@ __all__ = [ "AbstractComponentModeler", + "CoaxialLumpedPort", "ComponentModeler", - "Port", + "LumpedPort", "ModalPortDataArray", + "Port", + "PortDataArray", "TerminalComponentModeler", - "CoaxialLumpedPort", - "LumpedPort", - "WavePort", "TerminalPortDataArray", - "PortDataArray", + "WavePort", ] diff --git a/tidy3d/plugins/smatrix/component_modelers/base.py b/tidy3d/plugins/smatrix/component_modelers/base.py index e8467f2799..24a737a384 100644 --- a/tidy3d/plugins/smatrix/component_modelers/base.py +++ b/tidy3d/plugins/smatrix/component_modelers/base.py @@ -4,25 +4,25 @@ import os from abc import ABC, abstractmethod -from typing import Dict, Tuple, Union, get_args +from typing import Optional, Union, get_args import numpy as np import pydantic.v1 as pd -from ....components.base import Tidy3dBaseModel, cached_property -from ....components.data.data_array import DataArray -from ....components.data.sim_data import SimulationData -from ....components.simulation import Simulation -from ....components.types import FreqArray -from ....config import config -from ....constants import HERTZ -from ....exceptions import SetupError, Tidy3dKeyError -from ....log import log -from ....web.api.container import Batch, BatchData -from ..ports.coaxial_lumped import CoaxialLumpedPort -from ..ports.modal import Port -from ..ports.rectangular_lumped import LumpedPort -from ..ports.wave import WavePort +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.data.data_array import DataArray +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.simulation import Simulation +from tidy3d.components.types import FreqArray +from tidy3d.config import config +from tidy3d.constants import HERTZ +from tidy3d.exceptions import SetupError, Tidy3dKeyError +from tidy3d.log import log +from tidy3d.plugins.smatrix.ports.coaxial_lumped import CoaxialLumpedPort +from tidy3d.plugins.smatrix.ports.modal import Port +from tidy3d.plugins.smatrix.ports.rectangular_lumped import LumpedPort +from tidy3d.plugins.smatrix.ports.wave import WavePort +from tidy3d.web.api.container import Batch, BatchData # fwidth of gaussian pulse in units of central frequency FWIDTH_FRAC = 1.0 / 10 @@ -41,7 +41,7 @@ class AbstractComponentModeler(ABC, Tidy3dBaseModel): description="Simulation describing the device without any sources present.", ) - ports: Tuple[Union[Port, TerminalPortType], ...] = pd.Field( + ports: tuple[Union[Port, TerminalPortType], ...] = pd.Field( (), title="Ports", description="Collection of ports describing the scattering matrix elements. " @@ -132,14 +132,14 @@ def _warn_rf_license(cls, val): return val @staticmethod - def _task_name(port: Port, mode_index: int = None) -> str: + def _task_name(port: Port, mode_index: Optional[int] = None) -> str: """The name of a task, determined by the port of the source and mode index, if given.""" if mode_index is not None: return f"smatrix_{port.name}_{mode_index}" return f"smatrix_{port.name}" @cached_property - def sim_dict(self) -> Dict[str, Simulation]: + def sim_dict(self) -> dict[str, Simulation]: """Generate all the :class:`.Simulation` objects for the S matrix calculation.""" def to_file(self, fname: str) -> None: diff --git a/tidy3d/plugins/smatrix/component_modelers/modal.py b/tidy3d/plugins/smatrix/component_modelers/modal.py index c0acdf7fae..251d48252a 100644 --- a/tidy3d/plugins/smatrix/component_modelers/modal.py +++ b/tidy3d/plugins/smatrix/component_modelers/modal.py @@ -4,26 +4,27 @@ # "ModalPort" to explicitly differentiate these from "TerminalComponentModeler" and "LumpedPort". from __future__ import annotations -from typing import Dict, List, Optional, Tuple +from typing import Optional import numpy as np import pydantic.v1 as pd -from ....components.base import cached_property -from ....components.data.sim_data import SimulationData -from ....components.monitor import ModeMonitor -from ....components.simulation import Simulation -from ....components.source.field import ModeSource -from ....components.source.time import GaussianPulse -from ....components.types import Ax, Complex -from ....components.viz import add_ax_if_none, equal_aspect -from ....exceptions import SetupError -from ....web.api.container import BatchData -from ..ports.modal import ModalPortDataArray, Port +from tidy3d.components.base import cached_property +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.monitor import ModeMonitor +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.field import ModeSource +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.types import Ax, Complex +from tidy3d.components.viz import add_ax_if_none, equal_aspect +from tidy3d.exceptions import SetupError +from tidy3d.plugins.smatrix.ports.modal import ModalPortDataArray, Port +from tidy3d.web.api.container import BatchData + from .base import FWIDTH_FRAC, AbstractComponentModeler -MatrixIndex = Tuple[str, pd.NonNegativeInt] # the 'i' in S_ij -Element = Tuple[MatrixIndex, MatrixIndex] # the 'ij' in S_ij +MatrixIndex = tuple[str, pd.NonNegativeInt] # the 'i' in S_ij +Element = tuple[MatrixIndex, MatrixIndex] # the 'ij' in S_ij class ComponentModeler(AbstractComponentModeler): @@ -39,14 +40,14 @@ class ComponentModeler(AbstractComponentModeler): * `Computing the scattering matrix of a device <../../notebooks/SMatrix.html>`_ """ - ports: Tuple[Port, ...] = pd.Field( + ports: tuple[Port, ...] = pd.Field( (), title="Ports", description="Collection of ports describing the scattering matrix elements. " "For each input mode, one simulation will be run with a modal source.", ) - element_mappings: Tuple[Tuple[Element, Element, Complex], ...] = pd.Field( + element_mappings: tuple[tuple[Element, Element, Complex], ...] = pd.Field( (), title="Element Mappings", description="Mapping between elements of the scattering matrix, " @@ -59,7 +60,7 @@ class ComponentModeler(AbstractComponentModeler): "is skipped automatically.", ) - run_only: Optional[Tuple[MatrixIndex, ...]] = pd.Field( + run_only: Optional[tuple[MatrixIndex, ...]] = pd.Field( None, title="Run Only", description="If given, a tuple of matrix indices, specified by (:class:`.Port`, ``int``)," @@ -93,7 +94,7 @@ def _sim_has_no_sources(cls, val): return val @cached_property - def sim_dict(self) -> Dict[str, Simulation]: + def sim_dict(self) -> dict[str, Simulation]: """Generate all the :class:`.Simulation` objects for the S matrix calculation.""" sim_dict = {} @@ -106,13 +107,13 @@ def sim_dict(self) -> Dict[str, Simulation]: mode_source = self.to_source(port=port_source, mode_index=mode_index) new_mnts = list(self.simulation.monitors) + mode_monitors - sim_copy = self.simulation.copy(update=dict(sources=[mode_source], monitors=new_mnts)) + sim_copy = self.simulation.copy(update={"sources": [mode_source], "monitors": new_mnts}) task_name = self._task_name(port=port, mode_index=mode_index) sim_dict[task_name] = sim_copy return sim_dict @cached_property - def matrix_indices_monitor(self) -> Tuple[MatrixIndex, ...]: + def matrix_indices_monitor(self) -> tuple[MatrixIndex, ...]: """Tuple of all the possible matrix indices (port, mode_index) in the Component Modeler.""" matrix_indices = [] for port in self.ports: @@ -121,14 +122,14 @@ def matrix_indices_monitor(self) -> Tuple[MatrixIndex, ...]: return tuple(matrix_indices) @cached_property - def matrix_indices_source(self) -> Tuple[MatrixIndex, ...]: + def matrix_indices_source(self) -> tuple[MatrixIndex, ...]: """Tuple of all the source matrix indices (port, mode_index) in the Component Modeler.""" if self.run_only is not None: return self.run_only return self.matrix_indices_monitor @cached_property - def matrix_indices_run_sim(self) -> Tuple[MatrixIndex, ...]: + def matrix_indices_run_sim(self) -> tuple[MatrixIndex, ...]: """Tuple of all the source matrix indices (port, mode_index) in the Component Modeler.""" if self.element_mappings is None or self.element_mappings == {}: @@ -154,10 +155,10 @@ def matrix_indices_run_sim(self) -> Tuple[MatrixIndex, ...]: return source_indices_needed @cached_property - def port_names(self) -> Tuple[List[str], List[str]]: + def port_names(self) -> tuple[list[str], list[str]]: """List of port names for inputs and outputs, respectively.""" - def get_port_names(matrix_elements: Tuple[str, int]) -> List[str]: + def get_port_names(matrix_elements: tuple[str, int]) -> list[str]: """Get the port names from a list of (port name, mode index).""" port_names = [] for port_name, _ in matrix_elements: @@ -182,7 +183,7 @@ def to_monitor(self, port: Port) -> ModeMonitor: def to_source( self, port: Port, mode_index: int, num_freqs: int = 1, **kwargs - ) -> List[ModeSource]: + ) -> list[ModeSource]: """Creates a list of mode sources from a given port.""" freq0 = np.mean(self.freqs) fdiff = max(self.freqs) - min(self.freqs) @@ -205,25 +206,36 @@ def shift_port(self, port: Port) -> Port: shift_value = self._shift_value_signed(port=port) center_shifted = list(port.center) center_shifted[port.size.index(0.0)] += shift_value - port_shifted = port.copy(update=dict(center=center_shifted)) + port_shifted = port.copy(update={"center": center_shifted}) return port_shifted @equal_aspect @add_ax_if_none - def plot_sim(self, x: float = None, y: float = None, z: float = None, ax: Ax = None) -> Ax: + def plot_sim( + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + ) -> Ax: """Plot a :class:`.Simulation` with all sources added for each port, for troubleshooting.""" plot_sources = [] for port_source in self.ports: mode_source_0 = self.to_source(port=port_source, mode_index=0) plot_sources.append(mode_source_0) - sim_plot = self.simulation.copy(update=dict(sources=plot_sources)) + sim_plot = self.simulation.copy(update={"sources": plot_sources}) return sim_plot.plot(x=x, y=y, z=z, ax=ax) @equal_aspect @add_ax_if_none def plot_sim_eps( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None, **kwargs + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + **kwargs, ) -> Ax: """Plot permittivity of the :class:`.Simulation` with all sources added for each port.""" @@ -231,7 +243,7 @@ def plot_sim_eps( for port_source in self.ports: mode_source_0 = self.to_source(port=port_source, mode_index=0) plot_sources.append(mode_source_0) - sim_plot = self.simulation.copy(update=dict(sources=plot_sources)) + sim_plot = self.simulation.copy(update={"sources": plot_sources}) return sim_plot.plot_eps(x=x, y=y, z=z, ax=ax, **kwargs) def _normalization_factor(self, port_source: Port, sim_data: SimulationData) -> complex: @@ -249,10 +261,10 @@ def _normalization_factor(self, port_source: Port, sim_data: SimulationData) -> return normalize_amps.values @cached_property - def max_mode_index(self) -> Tuple[int, int]: + def max_mode_index(self) -> tuple[int, int]: """maximum mode indices for the smatrix dataset for the in and out ports, respectively.""" - def get_max_mode_indices(matrix_elements: Tuple[str, int]) -> int: + def get_max_mode_indices(matrix_elements: tuple[str, int]) -> int: """Get the maximum mode index for a list of (port name, mode index).""" return max(mode_index for _, mode_index in matrix_elements) @@ -277,13 +289,13 @@ def _internal_construct_smatrix(self, batch_data: BatchData) -> ModalPortDataArr (len(port_names_out), len(port_names_in), num_modes_out, num_modes_in, len(self.freqs)), dtype=complex, ) - coords = dict( - port_out=port_names_out, - port_in=port_names_in, - mode_index_out=range(num_modes_out), - mode_index_in=range(num_modes_in), - f=np.array(self.freqs), - ) + coords = { + "port_out": port_names_out, + "port_in": port_names_in, + "mode_index_out": range(num_modes_out), + "mode_index_in": range(num_modes_in), + "f": np.array(self.freqs), + } s_matrix = ModalPortDataArray(values, coords=coords) # loop through source ports @@ -306,33 +318,33 @@ def _internal_construct_smatrix(self, batch_data: BatchData) -> ModalPortDataArr source_norm = self._normalization_factor(port_in, sim_data) s_matrix_elements = np.array(amp.data) / np.array(source_norm) s_matrix.loc[ - dict( - port_in=port_name_in, - mode_index_in=mode_index_in, - port_out=port_name_out, - mode_index_out=mode_index_out, - ) + { + "port_in": port_name_in, + "mode_index_in": mode_index_in, + "port_out": port_name_out, + "mode_index_out": mode_index_out, + } ] = s_matrix_elements # element can be determined by user-defined mapping for (row_in, col_in), (row_out, col_out), mult_by in self.element_mappings: port_out_from, mode_index_out_from = row_in port_in_from, mode_index_in_from = col_in - coords_from = dict( - port_in=port_in_from, - mode_index_in=mode_index_in_from, - port_out=port_out_from, - mode_index_out=mode_index_out_from, - ) + coords_from = { + "port_in": port_in_from, + "mode_index_in": mode_index_in_from, + "port_out": port_out_from, + "mode_index_out": mode_index_out_from, + } port_out_to, mode_index_out_to = row_out port_in_to, mode_index_in_to = col_out - coords_to = dict( - port_in=port_in_to, - mode_index_in=mode_index_in_to, - port_out=port_out_to, - mode_index_out=mode_index_out_to, - ) + coords_to = { + "port_in": port_in_to, + "mode_index_in": mode_index_in_to, + "port_out": port_out_to, + "mode_index_out": mode_index_out_to, + } s_matrix.loc[coords_to] = mult_by * s_matrix.loc[coords_from].values return s_matrix diff --git a/tidy3d/plugins/smatrix/component_modelers/terminal.py b/tidy3d/plugins/smatrix/component_modelers/terminal.py index ebd17b5046..0e5b9cad0a 100644 --- a/tidy3d/plugins/smatrix/component_modelers/terminal.py +++ b/tidy3d/plugins/smatrix/component_modelers/terminal.py @@ -2,36 +2,32 @@ from __future__ import annotations -from typing import Dict, Tuple, Union +from typing import Optional, Union import numpy as np import pydantic.v1 as pd -from ....components.base import cached_property -from ....components.data.data_array import ( - DataArray, - FreqDataArray, -) -from ....components.data.monitor_data import ( - MonitorData, -) -from ....components.data.sim_data import SimulationData -from ....components.geometry.utils_2d import snap_coordinate_to_grid -from ....components.microwave.data.monitor_data import AntennaMetricsData -from ....components.monitor import DirectivityMonitor -from ....components.simulation import Simulation -from ....components.source.time import GaussianPulse -from ....components.types import Ax -from ....components.viz import add_ax_if_none, equal_aspect -from ....constants import C_0, OHM -from ....exceptions import Tidy3dError, Tidy3dKeyError, ValidationError -from ....log import log -from ....web.api.container import BatchData -from ..data.terminal import PortDataArray, TerminalPortDataArray -from ..ports.base_lumped import AbstractLumpedPort -from ..ports.coaxial_lumped import CoaxialLumpedPort -from ..ports.rectangular_lumped import LumpedPort -from ..ports.wave import WavePort +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import DataArray, FreqDataArray +from tidy3d.components.data.monitor_data import MonitorData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.geometry.utils_2d import snap_coordinate_to_grid +from tidy3d.components.microwave.data.monitor_data import AntennaMetricsData +from tidy3d.components.monitor import DirectivityMonitor +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.types import Ax +from tidy3d.components.viz import add_ax_if_none, equal_aspect +from tidy3d.constants import C_0, OHM +from tidy3d.exceptions import SetupError, Tidy3dError, Tidy3dKeyError, ValidationError +from tidy3d.log import log +from tidy3d.plugins.smatrix.data.terminal import PortDataArray, TerminalPortDataArray +from tidy3d.plugins.smatrix.ports.base_lumped import AbstractLumpedPort +from tidy3d.plugins.smatrix.ports.coaxial_lumped import CoaxialLumpedPort +from tidy3d.plugins.smatrix.ports.rectangular_lumped import LumpedPort +from tidy3d.plugins.smatrix.ports.wave import WavePort +from tidy3d.web.api.container import BatchData + from .base import AbstractComponentModeler, TerminalPortType @@ -39,7 +35,7 @@ class TerminalComponentModeler(AbstractComponentModeler): """Tool for modeling two-terminal multiport devices and computing port parameters with lumped and wave ports.""" - ports: Tuple[TerminalPortType, ...] = pd.Field( + ports: tuple[TerminalPortType, ...] = pd.Field( (), title="Terminal Ports", description="Collection of lumped and wave ports associated with the network. " @@ -64,7 +60,12 @@ def _warn_rf_license(cls, values): @equal_aspect @add_ax_if_none def plot_sim( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None, **kwargs + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + **kwargs, ) -> Ax: """Plot a :class:`.Simulation` with all sources added for each port, for troubleshooting.""" @@ -72,13 +73,18 @@ def plot_sim( for port_source in self.ports: source_0 = port_source.to_source(self._source_time) plot_sources.append(source_0) - sim_plot = self.simulation.copy(update=dict(sources=plot_sources)) + sim_plot = self.simulation.copy(update={"sources": plot_sources}) return sim_plot.plot(x=x, y=y, z=z, ax=ax, **kwargs) @equal_aspect @add_ax_if_none def plot_sim_eps( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None, **kwargs + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, + **kwargs, ) -> Ax: """Plot permittivity of the :class:`.Simulation` with all sources added for each port.""" @@ -86,11 +92,11 @@ def plot_sim_eps( for port_source in self.ports: source_0 = port_source.to_source(self._source_time) plot_sources.append(source_0) - sim_plot = self.simulation.copy(update=dict(sources=plot_sources)) + sim_plot = self.simulation.copy(update={"sources": plot_sources}) return sim_plot.plot_eps(x=x, y=y, z=z, ax=ax, **kwargs) @cached_property - def sim_dict(self) -> Dict[str, Simulation]: + def sim_dict(self) -> dict[str, Simulation]: """Generate all the :class:`.Simulation` objects for the port parameter calculation.""" sim_dict = {} @@ -110,7 +116,7 @@ def sim_dict(self) -> Dict[str, Simulation]: sim_wo_source = self.simulation.updated_copy( grid_spec=grid_spec, lumped_elements=lumped_resistors ) - snap_centers = dict() + snap_centers = {} for port in self._lumped_ports: port_center_on_axis = port.center[port.injection_axis] new_port_center = snap_coordinate_to_grid( @@ -136,10 +142,18 @@ def sim_dict(self) -> Dict[str, Simulation]: port.to_load(snap_center=snap_centers[port.name]) for port in self._lumped_ports ] - update_dict = dict( - monitors=new_mnts, - lumped_elements=new_lumped_elements, - ) + # Add mesh overrides for any wave ports present + mesh_overrides = list(sim_wo_source.grid_spec.override_structures) + for wave_port in self._wave_ports: + if wave_port.num_grid_cells is not None: + mesh_overrides.extend(wave_port.to_mesh_overrides()) + new_grid_spec = sim_wo_source.grid_spec.updated_copy(override_structures=mesh_overrides) + + update_dict = { + "monitors": new_mnts, + "lumped_elements": new_lumped_elements, + "grid_spec": new_grid_spec, + } # This is the new default simulation will all shared components added sim_wo_source = sim_wo_source.copy(update=update_dict) @@ -152,10 +166,6 @@ def sim_dict(self) -> Dict[str, Simulation]: task_name = self._task_name(port=port) sim_dict[task_name] = sim_wo_source.updated_copy(sources=[port_source]) - # Check final simulations for grid size at lumped ports - for _, sim in sim_dict.items(): - TerminalComponentModeler._check_grid_size_at_ports(sim, self._lumped_ports) - # Now, create simulations with wave port sources and mode solver monitors for computing port modes for wave_port in self._wave_ports: # Source is placed just before the field monitor of the port @@ -164,10 +174,16 @@ def sim_dict(self) -> Dict[str, Simulation]: ) port_source = wave_port.to_source(self._source_time, snap_center=mode_src_pos) - update_dict = dict(sources=[port_source]) + update_dict = {"sources": [port_source]} task_name = self._task_name(port=wave_port) sim_dict[task_name] = sim_wo_source.copy(update=update_dict) + + # Check final simulations for grid size at ports + for _, sim in sim_dict.items(): + TerminalComponentModeler._check_grid_size_at_ports(sim, self._lumped_ports) + TerminalComponentModeler._check_grid_size_at_wave_ports(sim, self._wave_ports) + return sim_dict @cached_property @@ -190,11 +206,11 @@ def _internal_construct_smatrix(self, batch_data: BatchData) -> TerminalPortData (len(self.freqs), len(port_names), len(port_names)), dtype=complex, ) - coords = dict( - f=np.array(self.freqs), - port_out=port_names, - port_in=port_names, - ) + coords = { + "f": np.array(self.freqs), + "port_out": port_names, + "port_in": port_names, + } a_matrix = TerminalPortDataArray(values, coords=coords) b_matrix = a_matrix.copy(deep=True) @@ -205,7 +221,7 @@ def _internal_construct_smatrix(self, batch_data: BatchData) -> TerminalPortData for port_in in self.ports: sim_data = batch_data[self._task_name(port=port_in)] a, b = self.compute_power_wave_amplitudes_at_each_port(port_impedances, sim_data) - indexer = dict(f=a.f, port_in=port_in.name, port_out=a.port) + indexer = {"f": a.f, "port_in": port_in.name, "port_out": a.port} a_matrix.loc[indexer] = a b_matrix.loc[indexer] = b @@ -236,12 +252,34 @@ def _validate_radiation_monitors(cls, val, values): return val @staticmethod - def _check_grid_size_at_ports(simulation: Simulation, ports: list[Union[AbstractLumpedPort]]): + def _check_grid_size_at_ports( + simulation: Simulation, ports: list[Union[LumpedPort, CoaxialLumpedPort]] + ): """Raises :class:`.SetupError` if the grid is too coarse at port locations""" yee_grid = simulation.grid.yee for port in ports: port._check_grid_size(yee_grid) + @staticmethod + def _check_grid_size_at_wave_ports(simulation: Simulation, ports: list[WavePort]): + """Raises :class:`.SetupError` if the grid is too coarse at port locations""" + for port in ports: + disc_grid = simulation.discretize(port) + check_axes = port.transverse_axes + msg_header = f"'WavePort' '{port.name}' " + for axis in check_axes: + sim_size = simulation.size[axis] + dim_cells = disc_grid.num_cells[axis] + if sim_size > 0 and dim_cells <= 2: + small_dim = "xyz"[axis] + raise SetupError( + msg_header + f"is too small along the " + f"'{small_dim}' axis. Less than '3' grid cells were detected. " + "Please ensure that the port's 'num_grid_cells' is not 'None'. " + "You also may need to use an 'AutoGrid' or `QuasiUniformGrid` " + "for the simulation passed to the 'TerminalComponentModeler'." + ) + def compute_power_wave_amplitudes_at_each_port( self, port_reference_impedances: PortDataArray, sim_data: SimulationData ) -> tuple[PortDataArray, PortDataArray]: @@ -265,10 +303,10 @@ def compute_power_wave_amplitudes_at_each_port( (len(self.freqs), len(port_names)), dtype=complex, ) - coords = dict( - f=np.array(self.freqs), - port=port_names, - ) + coords = { + "f": np.array(self.freqs), + "port": port_names, + } V_matrix = PortDataArray(values, coords=coords) I_matrix = V_matrix.copy(deep=True) @@ -277,7 +315,7 @@ def compute_power_wave_amplitudes_at_each_port( for port_out in self.ports: V_out, I_out = self.compute_port_VI(port_out, sim_data) - indexer = dict(port=port_out.name) + indexer = {"port": port_out.name} V_matrix.loc[indexer] = V_out I_matrix.loc[indexer] = I_out @@ -434,7 +472,7 @@ def _port_reference_impedances(self, batch_data: BatchData) -> PortDataArray: (len(self.freqs), len(port_names)), dtype=complex, ) - coords = dict(f=np.array(self.freqs), port=port_names) + coords = {"f": np.array(self.freqs), "port": port_names} port_impedances = PortDataArray(values, coords=coords) for port in self.ports: if isinstance(port, WavePort): @@ -443,10 +481,10 @@ def _port_reference_impedances(self, batch_data: BatchData) -> PortDataArray: # WavePorts have a port impedance calculated from its associated modal field distribution # and is frequency dependent. impedances = port.compute_port_impedance(sim_data_port).values - port_impedances.loc[dict(port=port.name)] = impedances.squeeze() + port_impedances.loc[{"port": port.name}] = impedances.squeeze() else: # LumpedPorts have a constant reference impedance - port_impedances.loc[dict(port=port.name)] = np.full(len(self.freqs), port.impedance) + port_impedances.loc[{"port": port.name}] = np.full(len(self.freqs), port.impedance) port_impedances = TerminalComponentModeler._set_port_data_array_attributes(port_impedances) return port_impedances @@ -527,12 +565,14 @@ def _monitor_data_at_port_amplitude( if not isinstance(a_port, FreqDataArray): freqs = list(monitor_data.monitor.freqs) array_vals = a_port * np.ones(len(freqs)) - a_port = FreqDataArray(array_vals, coords=dict(f=freqs)) + a_port = FreqDataArray(array_vals, coords={"f": freqs}) scale_array = a_port / a_raw_port return monitor_data.scale_fields_by_freq_array(scale_array, method="nearest") def get_antenna_metrics_data( - self, port_amplitudes: dict[str, complex] = None, monitor_name: str = None + self, + port_amplitudes: Optional[dict[str, complex]] = None, + monitor_name: Optional[str] = None, ) -> AntennaMetricsData: """Calculate antenna parameters using superposition of fields from multiple port excitations. @@ -574,7 +614,7 @@ def get_antenna_metrics_data( # Create data arrays for holding the superposition of all port power wave amplitudes f = list(rad_mon.freqs) - coords = dict(f=f, port=port_names) + coords = {"f": f, "port": port_names} a_sum = PortDataArray(np.zeros((len(f), len(port_names)), dtype=complex), coords=coords) b_sum = a_sum.copy() # Retrieve associated simulation data diff --git a/tidy3d/plugins/smatrix/data/terminal.py b/tidy3d/plugins/smatrix/data/terminal.py index 6a240a1dd0..39917d6a46 100644 --- a/tidy3d/plugins/smatrix/data/terminal.py +++ b/tidy3d/plugins/smatrix/data/terminal.py @@ -4,12 +4,9 @@ import pydantic.v1 as pd +from tidy3d.components.data.data_array import DataArray from tidy3d.log import log -from ....components.data.data_array import ( - DataArray, -) - class PortDataArray(DataArray): """Array of values over dimensions of frequency and port name. diff --git a/tidy3d/plugins/smatrix/ports/base_lumped.py b/tidy3d/plugins/smatrix/ports/base_lumped.py index e0bc3b0147..2871da304a 100644 --- a/tidy3d/plugins/smatrix/ports/base_lumped.py +++ b/tidy3d/plugins/smatrix/ports/base_lumped.py @@ -1,17 +1,20 @@ """Class and custom data array for representing a scattering matrix port based on lumped circuit elements.""" +from __future__ import annotations + from abc import abstractmethod from typing import Optional import pydantic.v1 as pd -from ....components.base import cached_property -from ....components.geometry.utils_2d import snap_coordinate_to_grid -from ....components.grid.grid import Grid, YeeGrid -from ....components.lumped_element import LumpedElementType -from ....components.monitor import FieldMonitor -from ....components.types import Complex, Coordinate, FreqArray -from ....constants import OHM +from tidy3d.components.base import cached_property +from tidy3d.components.geometry.utils_2d import snap_coordinate_to_grid +from tidy3d.components.grid.grid import Grid, YeeGrid +from tidy3d.components.lumped_element import LumpedElementType +from tidy3d.components.monitor import FieldMonitor +from tidy3d.components.types import Complex, Coordinate, FreqArray +from tidy3d.constants import OHM + from .base_terminal import AbstractTerminalPort DEFAULT_PORT_NUM_CELLS = 3 @@ -64,19 +67,23 @@ def snapped_center(self, grid: Grid) -> Coordinate: @cached_property @abstractmethod - def to_load(self, snap_center: float = None) -> LumpedElementType: + def to_load(self, snap_center: Optional[float] = None) -> LumpedElementType: """Create a load from the lumped port.""" @abstractmethod - def to_voltage_monitor(self, freqs: FreqArray, snap_center: float = None) -> FieldMonitor: + def to_voltage_monitor( + self, freqs: FreqArray, snap_center: Optional[float] = None + ) -> FieldMonitor: """Field monitor to compute port voltage.""" @abstractmethod - def to_current_monitor(self, freqs: FreqArray, snap_center: float = None) -> FieldMonitor: + def to_current_monitor( + self, freqs: FreqArray, snap_center: Optional[float] = None + ) -> FieldMonitor: """Field monitor to compute port current.""" def to_monitors( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> list[FieldMonitor]: """Field monitors to compute port voltage and current.""" return [ diff --git a/tidy3d/plugins/smatrix/ports/base_terminal.py b/tidy3d/plugins/smatrix/ports/base_terminal.py index 88504856ce..24594e76b1 100644 --- a/tidy3d/plugins/smatrix/ports/base_terminal.py +++ b/tidy3d/plugins/smatrix/ports/base_terminal.py @@ -1,21 +1,22 @@ """Class and custom data array for representing a scattering-matrix port, which is defined by a pair of terminals.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import Union +from typing import Optional, Union import pydantic.v1 as pd +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.data.data_array import FreqDataArray +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.grid.grid import Grid +from tidy3d.components.monitor import FieldMonitor, ModeMonitor +from tidy3d.components.source.base import Source +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.types import FreqArray from tidy3d.log import log -from ....components.base import Tidy3dBaseModel, cached_property -from ....components.data.data_array import FreqDataArray -from ....components.data.sim_data import SimulationData -from ....components.grid.grid import Grid -from ....components.monitor import FieldMonitor, ModeMonitor -from ....components.source.base import Source -from ....components.source.time import GaussianPulse -from ....components.types import FreqArray - class AbstractTerminalPort(Tidy3dBaseModel, ABC): """Class representing a single terminal-based port. All terminal ports must provide methods @@ -37,12 +38,12 @@ def injection_axis(self): @abstractmethod def to_source( - self, source_time: GaussianPulse, snap_center: float = None, grid: Grid = None + self, source_time: GaussianPulse, snap_center: Optional[float] = None, grid: Grid = None ) -> Source: """Create a current source from a terminal-based port.""" def to_field_monitors( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> Union[list[FieldMonitor], list[ModeMonitor]]: """DEPRECATED: Monitors used to compute the port voltage and current.""" log.warning( @@ -53,7 +54,7 @@ def to_field_monitors( @abstractmethod def to_monitors( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> Union[list[FieldMonitor], list[ModeMonitor]]: """Monitors used to compute the port voltage and current.""" diff --git a/tidy3d/plugins/smatrix/ports/coaxial_lumped.py b/tidy3d/plugins/smatrix/ports/coaxial_lumped.py index 51a0faef31..44655bffc0 100644 --- a/tidy3d/plugins/smatrix/ports/coaxial_lumped.py +++ b/tidy3d/plugins/smatrix/ports/coaxial_lumped.py @@ -1,25 +1,30 @@ """Lumped port specialization with an annular geometry for exciting coaxial ports.""" +from __future__ import annotations + +from typing import Optional + import numpy as np import pydantic.v1 as pd -from ....components.base import cached_property -from ....components.data.data_array import FreqDataArray, ScalarFieldDataArray -from ....components.data.dataset import FieldDataset -from ....components.data.sim_data import SimulationData -from ....components.geometry.base import Box, Geometry -from ....components.geometry.utils_2d import increment_float -from ....components.grid.grid import Grid, YeeGrid -from ....components.lumped_element import CoaxialLumpedResistor -from ....components.monitor import FieldMonitor -from ....components.source.current import CustomCurrentSource -from ....components.source.time import GaussianPulse -from ....components.types import Axis, Coordinate, Direction, FreqArray, Size -from ....components.validators import skip_if_fields_missing -from ....constants import MICROMETER -from ....exceptions import SetupError, ValidationError -from ...microwave import CustomCurrentIntegral2D, VoltageIntegralAxisAligned -from ...microwave.path_integrals import AbstractAxesRH +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import FreqDataArray, ScalarFieldDataArray +from tidy3d.components.data.dataset import FieldDataset +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.geometry.base import Box, Geometry +from tidy3d.components.geometry.utils_2d import increment_float +from tidy3d.components.grid.grid import Grid, YeeGrid +from tidy3d.components.lumped_element import CoaxialLumpedResistor +from tidy3d.components.monitor import FieldMonitor +from tidy3d.components.source.current import CustomCurrentSource +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.types import Axis, Coordinate, Direction, FreqArray, Size +from tidy3d.components.validators import skip_if_fields_missing +from tidy3d.constants import MICROMETER +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.plugins.microwave import CustomCurrentIntegral2D, VoltageIntegralAxisAligned +from tidy3d.plugins.microwave.path_integrals import AbstractAxesRH + from .base_lumped import AbstractLumpedPort DEFAULT_COAX_SOURCE_NUM_POINTS = 11 @@ -106,7 +111,7 @@ def _ensure_inner_diameter_is_smaller(cls, val, values): return val def to_source( - self, source_time: GaussianPulse, snap_center: float = None, grid: Grid = None + self, source_time: GaussianPulse, snap_center: Optional[float] = None, grid: Grid = None ) -> CustomCurrentSource: """Create a current source from the lumped port.""" # Discretized source amps are manually zeroed out later if they @@ -195,7 +200,7 @@ def compute_coax_current(rin, rout, x, y): current_dataset=dataset_E, ) - def to_load(self, snap_center: float = None) -> CoaxialLumpedResistor: + def to_load(self, snap_center: Optional[float] = None) -> CoaxialLumpedResistor: """Create a load resistor from the lumped port.""" # 2D materials are currently snapped to the grid, so snapping here is not needed. # Snapping is done here so plots of the simulation will more accurately portray the setup. @@ -214,7 +219,7 @@ def to_load(self, snap_center: float = None) -> CoaxialLumpedResistor: ) def to_voltage_monitor( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> FieldMonitor: """Field monitor to compute port voltage.""" center = list(self.center) @@ -238,7 +243,7 @@ def to_voltage_monitor( ) def to_current_monitor( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> FieldMonitor: """Field monitor to compute port current.""" center = list(self.center) @@ -351,8 +356,7 @@ def _determine_current_integral_pos( # We need to choose which side of the port to place the path integral, if direction == "+": return normal_coords[upper_bound] - else: - return normal_coords[lower_bound] + return normal_coords[lower_bound] @cached_property def _voltage_axis(self) -> Axis: @@ -380,7 +384,7 @@ def _check_grid_size(self, yee_grid: YeeGrid): """Raises :class:``SetupError`` if the grid is too coarse at port locations""" trans_axes = self.remaining_axes for axis in trans_axes: - e_component = "xyz"[trans_axes[0]] + e_component = "xyz"[axis] e_grid = yee_grid.grid_dict[f"E{e_component}"] coords = e_grid.to_dict[e_component] min_bound = self.center[axis] - self.outer_diameter / 2 diff --git a/tidy3d/plugins/smatrix/ports/modal.py b/tidy3d/plugins/smatrix/ports/modal.py index eb747d482c..eec551a80b 100644 --- a/tidy3d/plugins/smatrix/ports/modal.py +++ b/tidy3d/plugins/smatrix/ports/modal.py @@ -1,11 +1,13 @@ """Class and custom data array for representing a scattering matrix port based on waveguide modes.""" +from __future__ import annotations + import pydantic.v1 as pd -from ....components.data.data_array import DataArray -from ....components.geometry.base import Box -from ....components.mode_spec import ModeSpec -from ....components.types import Direction +from tidy3d.components.data.data_array import DataArray +from tidy3d.components.geometry.base import Box +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.types import Direction class ModalPortDataArray(DataArray): diff --git a/tidy3d/plugins/smatrix/ports/rectangular_lumped.py b/tidy3d/plugins/smatrix/ports/rectangular_lumped.py index 507a80f1c4..68aeb979f9 100644 --- a/tidy3d/plugins/smatrix/ports/rectangular_lumped.py +++ b/tidy3d/plugins/smatrix/ports/rectangular_lumped.py @@ -1,35 +1,33 @@ """Lumped port specialization with a rectangular geometry.""" +from __future__ import annotations + +from typing import Optional + import numpy as np import pydantic.v1 as pd -from ....components.base import cached_property -from ....components.data.data_array import FreqDataArray -from ....components.data.sim_data import SimulationData -from ....components.geometry.base import Box -from ....components.geometry.utils import ( +from tidy3d.components.base import cached_property +from tidy3d.components.data.data_array import FreqDataArray +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.geometry.base import Box +from tidy3d.components.geometry.utils import ( SnapBehavior, SnapLocation, SnappingSpec, snap_box_to_grid, ) -from ....components.geometry.utils_2d import increment_float -from ....components.grid.grid import Grid, YeeGrid -from ....components.lumped_element import ( - LinearLumpedElement, - LumpedResistor, - RLCNetwork, -) -from ....components.monitor import FieldMonitor -from ....components.source.current import UniformCurrentSource -from ....components.source.time import GaussianPulse -from ....components.types import Axis, FreqArray, LumpDistType -from ....components.validators import assert_line_or_plane -from ....exceptions import SetupError, ValidationError -from ...microwave import ( - CurrentIntegralAxisAligned, - VoltageIntegralAxisAligned, -) +from tidy3d.components.geometry.utils_2d import increment_float +from tidy3d.components.grid.grid import Grid, YeeGrid +from tidy3d.components.lumped_element import LinearLumpedElement, LumpedResistor, RLCNetwork +from tidy3d.components.monitor import FieldMonitor +from tidy3d.components.source.current import UniformCurrentSource +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.types import Axis, FreqArray, LumpDistType +from tidy3d.components.validators import assert_line_or_plane +from tidy3d.exceptions import SetupError, ValidationError +from tidy3d.plugins.microwave import CurrentIntegralAxisAligned, VoltageIntegralAxisAligned + from .base_lumped import AbstractLumpedPort @@ -99,7 +97,7 @@ def current_axis(self) -> Axis: return 3 - self.injection_axis - self.voltage_axis def to_source( - self, source_time: GaussianPulse, snap_center: float = None, grid: Grid = None + self, source_time: GaussianPulse, snap_center: Optional[float] = None, grid: Grid = None ) -> UniformCurrentSource: """Create a current source from the lumped port.""" if grid: @@ -126,7 +124,7 @@ def to_source( confine_to_bounds=True, ) - def to_load(self, snap_center: float = None) -> LumpedResistor: + def to_load(self, snap_center: Optional[float] = None) -> LumpedResistor: """Create a load resistor from the lumped port.""" # 2D materials are currently snapped to the grid, so snapping here is not needed. # It is done here so plots of the simulation will more accurately portray the setup @@ -148,7 +146,7 @@ def to_load(self, snap_center: float = None) -> LumpedResistor: ) def to_voltage_monitor( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> FieldMonitor: """Field monitor to compute port voltage.""" if grid: @@ -176,7 +174,7 @@ def to_voltage_monitor( ) def to_current_monitor( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> FieldMonitor: """Field monitor to compute port current.""" if grid: diff --git a/tidy3d/plugins/smatrix/ports/wave.py b/tidy3d/plugins/smatrix/ports/wave.py index e5532ef6a0..ee775fca40 100644 --- a/tidy3d/plugins/smatrix/ports/wave.py +++ b/tidy3d/plugins/smatrix/ports/wave.py @@ -1,30 +1,35 @@ """Class and custom data array for representing a scattering matrix wave port.""" +from __future__ import annotations + from typing import Optional, Union import numpy as np import pydantic.v1 as pd -from ....components.base import cached_property, skip_if_fields_missing -from ....components.data.data_array import FreqDataArray, FreqModeDataArray -from ....components.data.monitor_data import ModeData -from ....components.data.sim_data import SimulationData -from ....components.geometry.base import Box -from ....components.grid.grid import Grid -from ....components.monitor import ModeMonitor -from ....components.simulation import Simulation -from ....components.source.field import ModeSource, ModeSpec -from ....components.source.time import GaussianPulse -from ....components.types import Bound, Direction, FreqArray -from ....exceptions import ValidationError -from ...microwave import ( - CurrentIntegralTypes, - ImpedanceCalculator, - VoltageIntegralTypes, -) -from ...mode import ModeSolver +from tidy3d.components.base import cached_property, skip_if_fields_missing +from tidy3d.components.data.data_array import FreqDataArray, FreqModeDataArray +from tidy3d.components.data.monitor_data import ModeData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.geometry.base import Box +from tidy3d.components.geometry.bound_ops import bounds_contains +from tidy3d.components.grid.grid import Grid +from tidy3d.components.monitor import ModeMonitor +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.field import ModeSource, ModeSpec +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.structure import MeshOverrideStructure +from tidy3d.components.types import Axis, Direction, FreqArray +from tidy3d.constants import fp_eps +from tidy3d.exceptions import ValidationError +from tidy3d.plugins.microwave import CurrentIntegralTypes, ImpedanceCalculator, VoltageIntegralTypes +from tidy3d.plugins.mode import ModeSolver + from .base_terminal import AbstractTerminalPort +DEFAULT_WAVE_PORT_NUM_CELLS = 5 +MIN_WAVE_PORT_NUM_CELLS = 3 + class WavePort(AbstractTerminalPort, Box): """Class representing a single wave port""" @@ -62,6 +67,15 @@ class WavePort(AbstractTerminalPort, Box): description="Definition of current integral used to compute current and the characteristic impedance.", ) + num_grid_cells: Optional[int] = pd.Field( + DEFAULT_WAVE_PORT_NUM_CELLS, + ge=MIN_WAVE_PORT_NUM_CELLS, + title="Number of Grid Cells", + description="Number of mesh grid cells in the transverse plane of the `WavePort`. " + "Used in generating the suggested list of :class:`.MeshOverrideStructure` objects. " + "Must be greater than or equal to 3. When set to `None`, no grid refinement is performed.", + ) + def _mode_voltage_coefficients(self, mode_data: ModeData) -> FreqModeDataArray: """Calculates scaling coefficients to convert mode amplitudes to the total port voltage. @@ -87,16 +101,24 @@ def _mode_current_coefficients(self, mode_data: ModeData) -> FreqModeDataArray: return current_coeffs.squeeze() @cached_property - def injection_axis(self): + def injection_axis(self) -> Axis: """Injection axis of the port.""" return self.size.index(0.0) + @cached_property + def transverse_axes(self) -> tuple[Axis, Axis]: + """Transverse axes of the port.""" + _, trans_axes = Box.pop_axis([0, 1, 2], self.injection_axis) + return trans_axes + @cached_property def _mode_monitor_name(self) -> str: """Return the name of the :class:`.ModeMonitor` associated with this port.""" return f"{self.name}_mode" - def to_source(self, source_time: GaussianPulse, snap_center: float = None) -> ModeSource: + def to_source( + self, source_time: GaussianPulse, snap_center: Optional[float] = None + ) -> ModeSource: """Create a mode source from the wave port.""" center = list(self.center) if snap_center: @@ -112,7 +134,7 @@ def to_source(self, source_time: GaussianPulse, snap_center: float = None) -> Mo ) def to_monitors( - self, freqs: FreqArray, snap_center: float = None, grid: Grid = None + self, freqs: FreqArray, snap_center: Optional[float] = None, grid: Grid = None ) -> list[ModeMonitor]: """The wave port uses a :class:`.ModeMonitor` to compute the characteristic impedance and the port voltages and currents.""" @@ -183,14 +205,24 @@ def compute_port_impedance( impedance_array = impedance_calc.compute_impedance(mode_data) return impedance_array - @staticmethod - def _within_port_bounds(path_bounds: Bound, port_bounds: Bound) -> bool: - """Helper to check if one bounding box is completely within the other.""" - path_min = np.array(path_bounds[0]) - path_max = np.array(path_bounds[1]) - bound_min = np.array(port_bounds[0]) - bound_max = np.array(port_bounds[1]) - return (bound_min <= path_min).all() and (bound_max >= path_max).all() + def to_mesh_overrides(self) -> list[MeshOverrideStructure]: + """Creates a list of :class:`.MeshOverrideStructure` for mesh refinement in the transverse + plane of the port. The mode source requires at least 3 grid cells in the transverse + dimensions, so these mesh overrides will be added to the simulation to ensure that this + requirement is satisfied. + """ + dl = [None] * 3 + for trans_axis in self.transverse_axes: + dl[trans_axis] = self.size[trans_axis] / self.num_grid_cells + + return [ + MeshOverrideStructure( + geometry=Box(center=self.center, size=self.size), + dl=dl, + shadow=False, + priority=-1, + ) + ] @pd.validator("voltage_integral", "current_integral") def _validate_path_integrals_within_port(cls, val, values): @@ -198,7 +230,9 @@ def _validate_path_integrals_within_port(cls, val, values): center = values["center"] size = values["size"] box = Box(center=center, size=size) - if val and not WavePort._within_port_bounds(val.bounds, box.bounds): + if val and not bounds_contains( + box.bounds, val.bounds, fp_eps, np.finfo(np.float32).smallest_normal + ): raise ValidationError( f"'{cls.__name__}' must be setup with all path integrals defined within the bounds " f"of the port. Path bounds are '{val.bounds}', but port bounds are '{box.bounds}'." @@ -217,7 +251,7 @@ def _check_voltage_or_current(cls, val, values): return val @pd.validator("current_integral", always=True) - def validate_current_integral_sign(cls, val, values): + def _validate_current_integral_sign(cls, val, values): """ Validate that the sign of ``current_integral`` matches the port direction. """ diff --git a/tidy3d/plugins/smatrix/smatrix.py b/tidy3d/plugins/smatrix/smatrix.py index bb2e6d576a..8d244171a4 100644 --- a/tidy3d/plugins/smatrix/smatrix.py +++ b/tidy3d/plugins/smatrix/smatrix.py @@ -1,6 +1,7 @@ # backwards compatibility support for ``from tidy3d.plugins.smatrix.smatrix import `` +from __future__ import annotations from .component_modelers.modal import ComponentModeler from .ports.modal import Port -__all__ = ["Port", "ComponentModeler"] +__all__ = ["ComponentModeler", "Port"] diff --git a/tidy3d/plugins/waveguide/__init__.py b/tidy3d/plugins/waveguide/__init__.py index 8e468f2a33..cb43db72b6 100644 --- a/tidy3d/plugins/waveguide/__init__.py +++ b/tidy3d/plugins/waveguide/__init__.py @@ -1,5 +1,7 @@ """Waveguide utilities module""" +from __future__ import annotations + from .rectangular_dielectric import RectangularDielectric __all__ = ["RectangularDielectric"] diff --git a/tidy3d/plugins/waveguide/rectangular_dielectric.py b/tidy3d/plugins/waveguide/rectangular_dielectric.py index 78891e17bf..757f07bfd4 100644 --- a/tidy3d/plugins/waveguide/rectangular_dielectric.py +++ b/tidy3d/plugins/waveguide/rectangular_dielectric.py @@ -1,30 +1,31 @@ """Rectangular dielectric waveguide utilities.""" -from typing import Any, List, Tuple, Union +from __future__ import annotations + +from typing import Annotated, Any, Literal, Optional, Union import numpy import pydantic.v1 as pydantic from matplotlib import pyplot -from typing_extensions import Annotated - -from ...components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing -from ...components.boundary import BoundarySpec, Periodic -from ...components.data.data_array import FreqModeDataArray, ModeIndexDataArray -from ...components.geometry.base import Box -from ...components.geometry.polyslab import PolySlab -from ...components.grid.grid_spec import GridSpec -from ...components.medium import Medium, MediumType -from ...components.mode_spec import ModeSpec -from ...components.simulation import Simulation -from ...components.source.field import ModeSource -from ...components.source.time import GaussianPulse -from ...components.structure import Structure -from ...components.types import TYPE_TAG_STR, ArrayFloat1D, Ax, Axis, Coordinate, Literal, Size1D -from ...components.viz import add_ax_if_none -from ...constants import C_0, MICROMETER, RADIAN, inf -from ...exceptions import Tidy3dError, ValidationError -from ...log import log -from ..mode.mode_solver import ModeSolver + +from tidy3d.components.base import Tidy3dBaseModel, cached_property, skip_if_fields_missing +from tidy3d.components.boundary import BoundarySpec, Periodic +from tidy3d.components.data.data_array import FreqModeDataArray, ModeIndexDataArray +from tidy3d.components.geometry.base import Box +from tidy3d.components.geometry.polyslab import PolySlab +from tidy3d.components.grid.grid_spec import GridSpec +from tidy3d.components.medium import Medium, MediumType +from tidy3d.components.mode_spec import ModeSpec +from tidy3d.components.simulation import Simulation +from tidy3d.components.source.field import ModeSource +from tidy3d.components.source.time import GaussianPulse +from tidy3d.components.structure import Structure +from tidy3d.components.types import TYPE_TAG_STR, ArrayFloat1D, Ax, Axis, Coordinate, Size1D +from tidy3d.components.viz import add_ax_if_none +from tidy3d.constants import C_0, MICROMETER, RADIAN, inf +from tidy3d.exceptions import Tidy3dError, ValidationError +from tidy3d.log import log +from tidy3d.plugins.mode.mode_solver import ModeSolver AnnotatedMedium = Annotated[MediumType, pydantic.Field(discriminator=TYPE_TAG_STR)] @@ -72,14 +73,14 @@ class RectangularDielectric(Tidy3dBaseModel): discriminator=TYPE_TAG_STR, ) - clad_medium: Union[AnnotatedMedium, Tuple[AnnotatedMedium, ...]] = pydantic.Field( + clad_medium: Union[AnnotatedMedium, tuple[AnnotatedMedium, ...]] = pydantic.Field( ..., title="Clad Medium", description="Medium associated with the upper cladding layer. A sequence of mediums can " "be used to create a layered clad.", ) - box_medium: Union[AnnotatedMedium, Tuple[AnnotatedMedium, ...]] = pydantic.Field( + box_medium: Union[AnnotatedMedium, tuple[AnnotatedMedium, ...]] = pydantic.Field( None, title="Box Medium", description="Medium associated with the lower cladding layer. A sequence of mediums can " @@ -339,14 +340,14 @@ def _ensure_consistency(cls, values): return values @property - def _clad_medium(self) -> Tuple[MediumType, ...]: + def _clad_medium(self) -> tuple[MediumType, ...]: """Normalize data type to tuple.""" if not isinstance(self.clad_medium, tuple): return (self.clad_medium,) return self.clad_medium @property - def _box_medium(self) -> Tuple[MediumType, ...]: + def _box_medium(self) -> tuple[MediumType, ...]: """Normalize data type to tuple.""" if not isinstance(self.box_medium, tuple): return (self.box_medium,) @@ -373,7 +374,7 @@ def lateral_axis(self) -> Axis: def _swap_axis( self, lateral_coord: Any, normal_coord: Any, propagation_coord: Any - ) -> List[Any]: + ) -> list[Any]: """Swap the model coordinates to desired axes.""" result = [None, None, None] result[self.lateral_axis] = lateral_coord @@ -383,13 +384,13 @@ def _swap_axis( def _translate( self, lateral_coord: float, normal_coord: float, propagation_coord: float - ) -> List[float]: + ) -> list[float]: """Swap the model coordinates to desired axes and translate to origin.""" coordinates = self._swap_axis(lateral_coord, normal_coord, propagation_coord) result = [a + b for a, b in zip(self.origin, coordinates)] return result - def _transform_in_plane(self, lateral_coord: float, propagation_coord: float) -> List[float]: + def _transform_in_plane(self, lateral_coord: float, propagation_coord: float) -> list[float]: """Swap the model coordinates to desired axes in the substrate plane.""" result = self._translate(lateral_coord, 0, propagation_coord) _, result = Box.pop_axis(result, self.normal_axis) @@ -409,14 +410,14 @@ def width(self) -> Size1D: return w @property - def _core_starts(self) -> List[float]: + def _core_starts(self) -> list[float]: """Starting positions of each waveguide (x is the position in the lateral direction).""" core_x = [-0.5 * (self.core_width.sum() + self.gap.sum())] core_x.extend(core_x[0] + numpy.cumsum(self.core_width[:-1]) + numpy.cumsum(self.gap)) return core_x @property - def _override_structures(self) -> List[Structure]: + def _override_structures(self) -> list[Structure]: """Build override structures to define the simulation grid.""" # Grid resolution factor applied to the materials (increase for waveguide corners @@ -547,7 +548,7 @@ def grid_spec(self) -> GridSpec: return grid_spec @cached_property - def structures(self) -> List[Structure]: + def structures(self) -> list[Structure]: """Waveguide structures for simulation, including the core(s), slabs (if any), and bottom cladding, if different from the top. For bend modes, the structure is a 270 degree bend regardless of :attr:`length`.""" @@ -815,12 +816,12 @@ def mode_area(self) -> FreqModeDataArray: def plot( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, - source_alpha: float = None, - monitor_alpha: float = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, **patch_kwargs, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -857,13 +858,13 @@ def plot( def plot_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, - source_alpha: float = None, - monitor_alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, + source_alpha: Optional[float] = None, + monitor_alpha: Optional[float] = None, ax: Ax = None, ) -> Ax: """Plot each of simulation's components on a plane defined by one nonzero x,y,z coordinate. @@ -907,7 +908,11 @@ def plot_eps( ) def plot_structures( - self, x: float = None, y: float = None, z: float = None, ax: Ax = None + self, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + ax: Ax = None, ) -> Ax: """Plot each of simulation's structures on a plane defined by one nonzero x,y,z coordinate. @@ -936,11 +941,11 @@ def plot_structures( def plot_structures_eps( self, - x: float = None, - y: float = None, - z: float = None, - freq: float = None, - alpha: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, + freq: Optional[float] = None, + alpha: Optional[float] = None, cbar: bool = True, reverse: bool = False, ax: Ax = None, @@ -988,9 +993,9 @@ def plot_structures_eps( def plot_grid( self, - x: float = None, - y: float = None, - z: float = None, + x: Optional[float] = None, + y: Optional[float] = None, + z: Optional[float] = None, ax: Ax = None, **kwargs, ) -> Ax: @@ -1090,10 +1095,10 @@ def plot_field( val: Literal["real", "imag", "abs"] = "real", eps_alpha: float = 0.2, robust: bool = True, - vmin: float = None, - vmax: float = None, + vmin: Optional[float] = None, + vmax: Optional[float] = None, ax: Ax = None, - geometry_edges: str = None, + geometry_edges: Optional[str] = None, **sel_kwargs, ) -> Ax: """Plot the field for a :class:`.ModeSolverData` with :class:`.Simulation` plot overlaid. diff --git a/tidy3d/style.mplstyle b/tidy3d/style.mplstyle new file mode 100644 index 0000000000..4b5b62c122 --- /dev/null +++ b/tidy3d/style.mplstyle @@ -0,0 +1 @@ +axes.prop_cycle : cycler(color=["#176737", "#FF7B0D", "#979BAA", "#F44E6A", "#0062FF", "#26AB5B", "#6D3EF2", "#F59E0B"]) diff --git a/tidy3d/updater.py b/tidy3d/updater.py index 6e6228e3a9..bc7f017fab 100644 --- a/tidy3d/updater.py +++ b/tidy3d/updater.py @@ -4,7 +4,7 @@ import functools import json -from typing import Callable, Dict +from typing import Callable, Optional import pydantic.v1 as pd import yaml @@ -24,7 +24,7 @@ class Version(pd.BaseModel): minor: int @classmethod - def from_string(cls, string: str = None) -> Version: + def from_string(cls, string: Optional[str] = None) -> Version: """Return Version from a version string.""" if string is None: return cls.from_string(string=__version__) @@ -186,7 +186,7 @@ def new_update_function(sim_dict: dict) -> dict: return decorator -def iterate_update_dict(update_dict: Dict, update_types: Dict[str, Callable]): +def iterate_update_dict(update_dict: dict, update_types: dict[str, Callable]): """Recursively iterate nested ``update_dict``. For any nested ``nested_dict`` found, apply an update function if its ``nested_dict["type"]`` is in the keys of the ``update_types`` dictionary. Also iterates lists and tuples. @@ -194,7 +194,7 @@ def iterate_update_dict(update_dict: Dict, update_types: Dict[str, Callable]): if isinstance(update_dict, dict): # Update if we need to, and iterate recursively all items - if update_dict.get("type") in update_types.keys(): + if update_dict.get("type") in update_types: update_types[update_dict["type"]](update_dict) for item in update_dict.values(): iterate_update_dict(item, update_types) diff --git a/tidy3d/version.py b/tidy3d/version.py index eb0cb69796..a4f6f37051 100644 --- a/tidy3d/version.py +++ b/tidy3d/version.py @@ -1,3 +1,3 @@ -"""DO NOT EDIT: Modified automatically with .bump2version.cfg""" +from __future__ import annotations -__version__ = "2.8.4" +__version__ = "2.9.0" diff --git a/tidy3d/web/__init__.py b/tidy3d/web/__init__.py index 423e4dc18f..ff51cf9f3b 100644 --- a/tidy3d/web/__init__.py +++ b/tidy3d/web/__init__.py @@ -1,8 +1,11 @@ # ruff: noqa: E402 """imports interfaces for interacting with server""" -from ..log import get_logging_console, log -from ..version import __version__ +from __future__ import annotations + +from tidy3d.log import get_logging_console, log +from tidy3d.version import __version__ + from .core import core_config # set logger to tidy3d.log before it's invoked in other imports @@ -39,28 +42,28 @@ migrate() __all__ = [ - "run", - "upload", - "get_info", - "start", - "monitor", - "delete", + "Batch", + "BatchData", + "Job", "abort", - "download", - "load", - "estimate_cost", - "get_tasks", + "account", + "configure", + "delete", "delete_old", + "download", "download_json", "download_log", + "estimate_cost", + "get_info", + "get_tasks", + "load", "load_simulation", + "monitor", "real_cost", - "Job", - "Batch", - "BatchData", - "tidy3d_cli", - "configure", + "run", "run_async", + "start", "test", - "account", + "tidy3d_cli", + "upload", ] diff --git a/tidy3d/web/api/asynchronous.py b/tidy3d/web/api/asynchronous.py index fc50b1d349..91eacb5f18 100644 --- a/tidy3d/web/api/asynchronous.py +++ b/tidy3d/web/api/asynchronous.py @@ -1,22 +1,25 @@ """Interface to run several jobs in batch using simplified syntax.""" -from typing import Dict, List, Literal, Union +from __future__ import annotations + +from typing import Literal, Optional, Union + +from tidy3d.log import log +from tidy3d.web.core.types import PayType -from ...log import log -from ..core.types import PayType from .container import DEFAULT_DATA_DIR, Batch, BatchData from .tidy3d_stub import SimulationType def run_async( - simulations: Dict[str, SimulationType], + simulations: dict[str, SimulationType], folder_name: str = "default", path_dir: str = DEFAULT_DATA_DIR, - callback_url: str = None, - num_workers: int = None, + callback_url: Optional[str] = None, + num_workers: Optional[int] = None, verbose: bool = True, simulation_type: str = "tidy3d", - parent_tasks: Dict[str, List[str]] = None, + parent_tasks: Optional[dict[str, list[str]]] = None, reduce_simulation: Literal["auto", True, False] = "auto", pay_type: Union[PayType, str] = PayType.AUTO, ) -> BatchData: diff --git a/tidy3d/web/api/autograd/autograd.py b/tidy3d/web/api/autograd/autograd.py index c5e1f506b2..d0d842869d 100644 --- a/tidy3d/web/api/autograd/autograd.py +++ b/tidy3d/web/api/autograd/autograd.py @@ -1,4 +1,5 @@ # autograd wrapper for web functions +from __future__ import annotations import os import tempfile @@ -13,17 +14,17 @@ import tidy3d as td from tidy3d.components.autograd import AutogradFieldMap, get_static +from tidy3d.components.autograd.constants import MAX_NUM_ADJOINT_PER_FWD, MAX_NUM_TRACED_STRUCTURES from tidy3d.components.autograd.derivative_utils import DerivativeInfo -from tidy3d.components.types import Literal - -from ....exceptions import AdjointError -from ...core.s3utils import download_file, upload_file -from ...core.types import PayType -from ..asynchronous import DEFAULT_DATA_DIR -from ..asynchronous import run_async as run_async_webapi -from ..container import DEFAULT_DATA_PATH, Batch, BatchData, Job -from ..tidy3d_stub import SimulationDataType, SimulationType -from ..webapi import run as run_webapi +from tidy3d.exceptions import AdjointError +from tidy3d.web.api.asynchronous import DEFAULT_DATA_DIR +from tidy3d.web.api.asynchronous import run_async as run_async_webapi +from tidy3d.web.api.container import DEFAULT_DATA_PATH, Batch, BatchData, Job +from tidy3d.web.api.tidy3d_stub import SimulationDataType, SimulationType +from tidy3d.web.api.webapi import run as run_webapi +from tidy3d.web.core.s3utils import download_file, upload_file +from tidy3d.web.core.types import PayType + from .utils import E_to_D, FieldMap, TracerKeys, get_derivative_maps # keys for data into auxiliary dictionary @@ -35,9 +36,6 @@ SIM_VJP_FILE = "output/autograd_sim_vjp.hdf5" SIM_FIELDS_KEYS_FILE = "autograd_sim_fields_keys.hdf5" -MAX_NUM_TRACED_STRUCTURES = 500 -MAX_NUM_ADJOINT_PER_FWD = 10 - # default value for whether to do local gradient calculation (True) or server side (False) LOCAL_GRADIENT = False @@ -57,14 +55,14 @@ def is_valid_for_autograd(simulation: td.Simulation) -> bool: return False # if no tracers just use regular web.run() - traced_fields = simulation.strip_traced_fields( + traced_fields = simulation._strip_traced_fields( include_untraced_data_arrays=False, starting_path=("structures",) ) if not traced_fields: return False # if no frequency-domain data (e.g. only field time monitors), raise an error - if not simulation.freqs_adjoint: + if not simulation._freqs_adjoint: raise AdjointError( "No frequency-domain data found in simulation, but found traced structures. " "For an autograd run, you must have at least one frequency-domain monitor." @@ -96,18 +94,19 @@ def run( task_name: str, folder_name: str = "default", path: str = "simulation_data.hdf5", - callback_url: str = None, + callback_url: typing.Optional[str] = None, verbose: bool = True, - progress_callback_upload: typing.Callable[[float], None] = None, - progress_callback_download: typing.Callable[[float], None] = None, - solver_version: str = None, - worker_group: str = None, + progress_callback_upload: typing.Optional[typing.Callable[[float], None]] = None, + progress_callback_download: typing.Optional[typing.Callable[[float], None]] = None, + solver_version: typing.Optional[str] = None, + worker_group: typing.Optional[str] = None, simulation_type: str = "tidy3d", - parent_tasks: list[str] = None, + parent_tasks: typing.Optional[list[str]] = None, local_gradient: bool = LOCAL_GRADIENT, max_num_adjoint_per_fwd: int = MAX_NUM_ADJOINT_PER_FWD, - reduce_simulation: Literal["auto", True, False] = "auto", + reduce_simulation: typing.Literal["auto", True, False] = "auto", pay_type: typing.Union[PayType, str] = PayType.AUTO, + priority: typing.Optional[int] = None, ) -> SimulationDataType: """ Submits a :class:`.Simulation` to server, starts running, monitors progress, downloads, @@ -147,6 +146,8 @@ def run( Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver. pay_type: typing.Union[PayType, str] = PayType.AUTO Which method to pay for the simulation. + priority: int = None + Task priority for vGPU queue (1=lowest, 10=highest). Returns ------- Union[:class:`.SimulationData`, :class:`.HeatSimulationData`, :class:`.EMESimulationData`] @@ -191,6 +192,8 @@ def run( :meth:`tidy3d.web.api.container.Batch.monitor` Monitor progress of each of the running tasks. """ + if priority is not None and (priority < 1 or priority > 10): + raise ValueError("Priority must be between '1' and '10' if specified.") if is_valid_for_autograd(simulation): return _run( simulation=simulation, @@ -225,6 +228,7 @@ def run( parent_tasks=parent_tasks, reduce_simulation=reduce_simulation, pay_type=pay_type, + priority=priority, ) @@ -232,14 +236,14 @@ def run_async( simulations: dict[str, SimulationType], folder_name: str = "default", path_dir: str = DEFAULT_DATA_DIR, - callback_url: str = None, - num_workers: int = None, + callback_url: typing.Optional[str] = None, + num_workers: typing.Optional[int] = None, verbose: bool = True, simulation_type: str = "tidy3d", - parent_tasks: dict[str, list[str]] = None, + parent_tasks: typing.Optional[dict[str, list[str]]] = None, local_gradient: bool = LOCAL_GRADIENT, max_num_adjoint_per_fwd: int = MAX_NUM_ADJOINT_PER_FWD, - reduce_simulation: Literal["auto", True, False] = "auto", + reduce_simulation: typing.Literal["auto", True, False] = "auto", pay_type: typing.Union[PayType, str] = PayType.AUTO, ) -> BatchData: """Submits a set of Union[:class:`.Simulation`, :class:`.HeatSimulation`, :class:`.EMESimulation`] objects to server, @@ -404,7 +408,7 @@ def setup_run(simulation: td.Simulation) -> AutogradFieldMap: """Process a user-supplied ``Simulation`` into inputs to ``_run_primitive``.""" # get a mapping of all the traced fields in the provided simulation - return simulation.strip_traced_fields( + return simulation._strip_traced_fields( include_untraced_data_arrays=False, starting_path=("structures",) ) @@ -414,7 +418,7 @@ def postprocess_run(traced_fields_data: AutogradFieldMap, aux_data: dict) -> td. # grab the user's 'SimulationData' and return with the autograd-tracers inserted sim_data_original = aux_data[AUX_KEY_SIM_DATA_ORIGINAL] - return sim_data_original.insert_traced_fields(traced_fields_data) + return sim_data_original._insert_traced_fields(traced_fields_data) """ Autograd-traced Primitive for FWD pass ``run`` functions """ @@ -467,7 +471,7 @@ def _run_primitive( # TODO: put this in postprocess? aux_data[AUX_KEY_FWD_TASK_ID] = task_id_fwd aux_data[AUX_KEY_SIM_DATA_ORIGINAL] = sim_data_orig - field_map = sim_data_orig.strip_traced_fields( + field_map = sim_data_orig._strip_traced_fields( include_untraced_data_arrays=True, starting_path=("data",) ) @@ -531,7 +535,7 @@ def _run_async_primitive( sim_data_orig = sim_data_orig_dict[task_name] aux_data_dict[task_name][AUX_KEY_FWD_TASK_ID] = task_id_fwd aux_data_dict[task_name][AUX_KEY_SIM_DATA_ORIGINAL] = sim_data_orig - field_map = sim_data_orig.strip_traced_fields( + field_map = sim_data_orig._strip_traced_fields( include_untraced_data_arrays=True, starting_path=("data",) ) field_map_fwd_dict[task_name] = field_map @@ -548,7 +552,7 @@ def setup_fwd( # Always try to build the variant that includes adjoint monitors so that # errors in monitor placement are caught early. - sim_with_adj_mon = sim_original.with_adjoint_monitors(sim_fields) + sim_with_adj_mon = sim_original._with_adjoint_monitors(sim_fields) return sim_with_adj_mon if local_gradient else sim_original @@ -560,7 +564,7 @@ def postprocess_fwd( """Postprocess the combined simulation data into an Autograd field map.""" num_mnts_original = len(sim_original.monitors) - sim_data_original, sim_data_fwd = sim_data_combined.split_original_fwd( + sim_data_original, sim_data_fwd = sim_data_combined._split_original_fwd( num_mnts_original=num_mnts_original ) @@ -568,7 +572,7 @@ def postprocess_fwd( aux_data[AUX_KEY_SIM_DATA_FWD] = sim_data_fwd # strip out the tracer AutogradFieldMap for the .data from the original sim - data_traced = sim_data_original.strip_traced_fields( + data_traced = sim_data_original._strip_traced_fields( include_untraced_data_arrays=True, starting_path=("data",) ) @@ -704,7 +708,7 @@ def vjp(data_fields_vjp: AutogradFieldMap) -> AutogradFieldMap: # Build a per-task parent_tasks mapping parent_tasks = {} - for tname_adj in sims_adj_dict.keys(): + for tname_adj in sims_adj_dict: parent_tasks[tname_adj] = [task_id_fwd] run_kwargs["parent_tasks"] = parent_tasks @@ -900,7 +904,7 @@ def setup_adj( # start with the full simulation data structure and either zero out the fields # that have no tracer data for them or insert the tracer data - full_sim_data_dict = sim_data_orig.strip_traced_fields( + full_sim_data_dict = sim_data_orig._strip_traced_fields( include_untraced_data_arrays=True, starting_path=("data",) ) for path in full_sim_data_dict.keys(): @@ -910,17 +914,17 @@ def setup_adj( full_sim_data_dict[path] *= 0 # insert the raw VJP data into the .data of the original SimulationData - sim_data_vjp = sim_data_orig.insert_traced_fields(field_mapping=full_sim_data_dict) + sim_data_vjp = sim_data_orig._insert_traced_fields(field_mapping=full_sim_data_dict) # make adjoint simulation from that SimulationData data_vjp_paths = set(data_fields_vjp.keys()) num_monitors = len(sim_data_orig.simulation.monitors) - adjoint_monitors = sim_data_orig.simulation.with_adjoint_monitors(sim_fields_keys).monitors[ + adjoint_monitors = sim_data_orig.simulation._with_adjoint_monitors(sim_fields_keys).monitors[ num_monitors: ] - sims_adj = sim_data_vjp.make_adjoint_sims( + sims_adj = sim_data_vjp._make_adjoint_sims( data_vjp_paths=data_vjp_paths, adjoint_monitors=adjoint_monitors, ) @@ -978,10 +982,10 @@ def postprocess_adj( sim_fields_vjp = {} for structure_index, structure_paths in sim_vjp_map.items(): # grab the forward and adjoint data - E_fwd = sim_data_fwd.get_adjoint_data(structure_index, data_type="fld") - eps_fwd = sim_data_fwd.get_adjoint_data(structure_index, data_type="eps") - E_adj = sim_data_adj.get_adjoint_data(structure_index, data_type="fld") - eps_adj = sim_data_adj.get_adjoint_data(structure_index, data_type="eps") + E_fwd = sim_data_fwd._get_adjoint_data(structure_index, data_type="fld") + eps_fwd = sim_data_fwd._get_adjoint_data(structure_index, data_type="eps") + E_adj = sim_data_adj._get_adjoint_data(structure_index, data_type="fld") + eps_adj = sim_data_adj._get_adjoint_data(structure_index, data_type="eps") # post normalize the adjoint fields if a single, broadband source adj_flds_normed = {} @@ -1066,11 +1070,11 @@ def postprocess_adj( bounds_intersect=bounds_intersect, ) - vjp_value_map = structure.compute_derivatives(derivative_info) + vjp_value_map = structure._compute_derivatives(derivative_info) # extract VJPs and put back into sim_fields_vjp AutogradFieldMap for structure_path, vjp_value in vjp_value_map.items(): - sim_path = tuple(["structures", structure_index] + list(structure_path)) + sim_path = ("structures", structure_index, *list(structure_path)) if freq_idx == 0: sim_fields_vjp[sim_path] = vjp_value else: @@ -1099,7 +1103,7 @@ def postprocess_adj( def parse_run_kwargs(**run_kwargs): """Parse the ``run_kwargs`` to extract what should be passed to the ``Job`` initialization.""" - job_fields = list(Job._upload_fields) + ["solver_version", "pay_type"] + job_fields = [*list(Job._upload_fields), "solver_version", "pay_type"] job_init_kwargs = {k: v for k, v in run_kwargs.items() if k in job_fields} return job_init_kwargs diff --git a/tidy3d/web/api/autograd/utils.py b/tidy3d/web/api/autograd/utils.py index 1d5cd136c3..7189096531 100644 --- a/tidy3d/web/api/autograd/utils.py +++ b/tidy3d/web/api/autograd/utils.py @@ -22,7 +22,7 @@ def get_derivative_maps( """Get electric and displacement field derivative maps.""" der_map_E = derivative_map_E(fld_fwd=fld_fwd, fld_adj=fld_adj) der_map_D = derivative_map_D(fld_fwd=fld_fwd, eps_fwd=eps_fwd, fld_adj=fld_adj, eps_adj=eps_adj) - return dict(E=der_map_E, D=der_map_D) + return {"E": der_map_E, "D": der_map_D} def derivative_map_E(fld_fwd: td.FieldData, fld_adj: td.FieldData) -> td.FieldData: diff --git a/tidy3d/web/api/connect_util.py b/tidy3d/web/api/connect_util.py index 60e69320b4..137fe0d684 100644 --- a/tidy3d/web/api/connect_util.py +++ b/tidy3d/web/api/connect_util.py @@ -1,5 +1,7 @@ """connect util for webapi.""" +from __future__ import annotations + import time from functools import wraps @@ -8,8 +10,8 @@ from requests.exceptions import JSONDecodeError from urllib3.exceptions import NewConnectionError -from ...exceptions import WebError -from ...log import log +from tidy3d.exceptions import WebError +from tidy3d.log import log # number of seconds to keep re-trying connection before erroring CONNECTION_RETRY_TIME = 180 diff --git a/tidy3d/web/api/container.py b/tidy3d/web/api/container.py index 851cd35acd..e4ea5afaf4 100644 --- a/tidy3d/web/api/container.py +++ b/tidy3d/web/api/container.py @@ -8,21 +8,22 @@ from abc import ABC from collections.abc import Mapping from concurrent.futures import ThreadPoolExecutor -from typing import Dict, Optional, Tuple +from typing import Literal, Optional import pydantic.v1 as pd from rich.progress import BarColumn, Progress, TaskProgressColumn, TextColumn, TimeElapsedColumn -from ...components.base import Tidy3dBaseModel, cached_property -from ...components.mode.mode_solver import ModeSolver -from ...components.types import Literal, annotate_type -from ...exceptions import DataError -from ...log import get_logging_console, log -from ..api import webapi as web -from ..core.constants import TaskId, TaskName -from ..core.task_core import Folder -from ..core.task_info import RunInfo, TaskInfo -from ..core.types import PayType +from tidy3d.components.base import Tidy3dBaseModel, cached_property +from tidy3d.components.mode.mode_solver import ModeSolver +from tidy3d.components.types import annotate_type +from tidy3d.exceptions import DataError +from tidy3d.log import get_logging_console, log +from tidy3d.web.api import webapi as web +from tidy3d.web.core.constants import TaskId, TaskName +from tidy3d.web.core.task_core import Folder +from tidy3d.web.core.task_info import RunInfo, TaskInfo +from tidy3d.web.core.types import PayType + from .tidy3d_stub import SimulationDataType, SimulationType # Max # of workers for parallel upload / download: above 10, performance is same but with warnings @@ -41,7 +42,6 @@ class WebContainer(Tidy3dBaseModel, ABC): @abstractmethod def _check_path_dir(path: str) -> None: """Make sure local output directory exists and create it if not.""" - pass @staticmethod def _check_folder(folder_name: str) -> None: @@ -164,7 +164,7 @@ class Job(WebContainer): description="Type of simulation, used internally only.", ) - parent_tasks: Tuple[TaskId, ...] = pd.Field( + parent_tasks: tuple[TaskId, ...] = pd.Field( None, title="Parent Tasks", description="Tuple of parent task ids, used internally only." ) @@ -411,13 +411,13 @@ class BatchData(Tidy3dBaseModel, Mapping): * `Performing parallel / batch processing of simulations <../../notebooks/ParameterScan.html>`_ """ - task_paths: Dict[TaskName, str] = pd.Field( + task_paths: dict[TaskName, str] = pd.Field( ..., title="Data Paths", description="Mapping of task_name to path to corresponding data for each task in batch.", ) - task_ids: Dict[TaskName, str] = pd.Field( + task_ids: dict[TaskName, str] = pd.Field( ..., title="Task IDs", description="Mapping of task_name to task_id for each task in batch." ) @@ -499,7 +499,7 @@ class Batch(WebContainer): * `Inverse taper edge coupler <../../notebooks/EdgeCoupler.html>`_ """ - simulations: Dict[TaskName, annotate_type(SimulationType)] = pd.Field( + simulations: dict[TaskName, annotate_type(SimulationType)] = pd.Field( ..., title="Simulations", description="Mapping of task names to Simulations to run as a batch.", @@ -536,7 +536,7 @@ class Batch(WebContainer): description="Type of each simulation in the batch, used internally only.", ) - parent_tasks: Dict[str, Tuple[TaskId, ...]] = pd.Field( + parent_tasks: dict[str, tuple[TaskId, ...]] = pd.Field( None, title="Parent Tasks", description="Collection of parent task ids for each job in batch, used internally only.", @@ -563,7 +563,7 @@ class Batch(WebContainer): description="Specify the payment method.", ) - jobs_cached: Dict[TaskName, Job] = pd.Field( + jobs_cached: dict[TaskName, Job] = pd.Field( None, title="Jobs (Cached)", description="Optional field to specify ``jobs``. Only used as a workaround internally " @@ -610,7 +610,7 @@ def run(self, path_dir: str = DEFAULT_DATA_DIR) -> BatchData: return self.load(path_dir=path_dir) @cached_property - def jobs(self) -> Dict[TaskName, Job]: + def jobs(self) -> dict[TaskName, Job]: """Create a series of tasks in the :class:`.Batch` and upload them to server. Note @@ -694,7 +694,7 @@ def upload(self) -> None: completed += 1 progress.update(pbar, completed=completed) - def get_info(self) -> Dict[TaskName, TaskInfo]: + def get_info(self) -> dict[TaskName, TaskInfo]: """Get information about each task in the :class:`Batch`. Returns @@ -723,7 +723,7 @@ def start(self) -> None: for _, job in self.jobs.items(): executor.submit(job.start) - def get_run_info(self) -> Dict[TaskName, RunInfo]: + def get_run_info(self) -> dict[TaskName, RunInfo]: """get information about a each of the tasks in the :class:`Batch`. Returns @@ -881,7 +881,7 @@ def _job_data_path(task_id: TaskId, path_dir: str = DEFAULT_DATA_DIR): str Full path to the data file. """ - return os.path.join(path_dir, f"{str(task_id)}.hdf5") + return os.path.join(path_dir, f"{task_id!s}.hdf5") @staticmethod def _batch_path(path_dir: str = DEFAULT_DATA_DIR): diff --git a/tidy3d/web/api/material_fitter.py b/tidy3d/web/api/material_fitter.py index 0d91f825e5..82bb158736 100644 --- a/tidy3d/web/api/material_fitter.py +++ b/tidy3d/web/api/material_fitter.py @@ -12,9 +12,9 @@ import requests from pydantic.v1 import BaseModel, Field -from ...plugins.dispersion import DispersionFitter -from ..core.http_util import http -from ..core.types import Submittable +from tidy3d.plugins.dispersion import DispersionFitter +from tidy3d.web.core.http_util import http +from tidy3d.web.core.types import Submittable class ConstraintEnum(str, Enum): diff --git a/tidy3d/web/api/material_libray.py b/tidy3d/web/api/material_libray.py index 3b9e397f2c..98bfeaa0b2 100644 --- a/tidy3d/web/api/material_libray.py +++ b/tidy3d/web/api/material_libray.py @@ -2,14 +2,15 @@ from __future__ import annotations +import builtins import json -from typing import List, Optional +from typing import Optional from pydantic.v1 import Field, parse_obj_as, validator -from ...components.medium import MediumType -from ..core.http_util import http -from ..core.types import Queryable +from tidy3d.components.medium import MediumType +from tidy3d.web.core.http_util import http +from tidy3d.web.core.types import Queryable class MaterialLibray(Queryable, smart_union=True): @@ -31,7 +32,7 @@ def parse_result(cls, values): return json.loads(values) @classmethod - def list(cls) -> List[MaterialLibray]: + def list(cls) -> builtins.list[MaterialLibray]: """List all material libraries. Returns @@ -40,4 +41,4 @@ def list(cls) -> List[MaterialLibray]: List of material libraries/ """ resp = http.get("tidy3d/libraries") - return parse_obj_as(List[MaterialLibray], resp) if resp else None + return parse_obj_as(list[MaterialLibray], resp) if resp else None diff --git a/tidy3d/web/api/mode.py b/tidy3d/web/api/mode.py index 09024aeff8..02364f105b 100644 --- a/tidy3d/web/api/mode.py +++ b/tidy3d/web/api/mode.py @@ -7,28 +7,27 @@ import tempfile import time from datetime import datetime -from typing import Callable, List, Optional, Union +from typing import Callable, Literal, Optional, Union import pydantic.v1 as pydantic from botocore.exceptions import ClientError from joblib import Parallel, delayed from rich.progress import Progress -from ...components.data.monitor_data import ModeSolverData -from ...components.eme.simulation import EMESimulation -from ...components.medium import AbstractCustomMedium -from ...components.simulation import Simulation -from ...components.types import Literal -from ...exceptions import SetupError, WebError -from ...log import get_logging_console, log -from ...plugins.mode.mode_solver import MODE_MONITOR_NAME, ModeSolver -from ...version import __version__ -from ..core.core_config import get_logger_console -from ..core.environment import Env -from ..core.http_util import http -from ..core.s3utils import download_file, download_gz_file, upload_file -from ..core.task_core import Folder -from ..core.types import PayType, ResourceLifecycle, Submittable +from tidy3d.components.data.monitor_data import ModeSolverData +from tidy3d.components.eme.simulation import EMESimulation +from tidy3d.components.medium import AbstractCustomMedium +from tidy3d.components.simulation import Simulation +from tidy3d.exceptions import SetupError, WebError +from tidy3d.log import get_logging_console, log +from tidy3d.plugins.mode.mode_solver import MODE_MONITOR_NAME, ModeSolver +from tidy3d.version import __version__ +from tidy3d.web.core.core_config import get_logger_console +from tidy3d.web.core.environment import Env +from tidy3d.web.core.http_util import http +from tidy3d.web.core.s3utils import download_file, download_gz_file, upload_file +from tidy3d.web.core.task_core import Folder +from tidy3d.web.core.types import PayType, ResourceLifecycle, Submittable SIMULATION_JSON = "simulation.json" SIM_FILE_HDF5_GZ = "simulation.hdf5.gz" @@ -53,8 +52,8 @@ def run( folder_name: str = "Mode Solver", results_file: str = "mode_solver.hdf5", verbose: bool = True, - progress_callback_upload: Callable[[float], None] = None, - progress_callback_download: Callable[[float], None] = None, + progress_callback_upload: Optional[Callable[[float], None]] = None, + progress_callback_download: Optional[Callable[[float], None]] = None, reduce_simulation: Literal["auto", True, False] = "auto", pay_type: Union[PayType, str] = PayType.AUTO, ) -> ModeSolverData: @@ -147,17 +146,17 @@ def run( def run_batch( - mode_solvers: List[ModeSolver], + mode_solvers: list[ModeSolver], task_name: str = "BatchModeSolver", folder_name: str = "BatchModeSolvers", - results_files: List[str] = None, + results_files: Optional[list[str]] = None, verbose: bool = True, max_workers: int = DEFAULT_NUM_WORKERS, max_retries: int = DEFAULT_MAX_RETRIES, retry_delay: float = DEFAULT_RETRY_DELAY, - progress_callback_upload: Callable[[float], None] = None, - progress_callback_download: Callable[[float], None] = None, -) -> List[ModeSolverData]: + progress_callback_upload: Optional[Callable[[float], None]] = None, + progress_callback_download: Optional[Callable[[float], None]] = None, +) -> list[ModeSolverData]: """ Submits a batch of ModeSolver to the server concurrently, manages progress, and retrieves results. @@ -221,7 +220,7 @@ def handle_mode_solver(index, progress, pbar): progress.update(pbar, advance=1) return result except Exception as e: - console.log(f"Error in mode solver {index}: {str(e)}") + console.log(f"Error in mode solver {index}: {e!s}") if retries < max_retries: time.sleep(retry_delay) retries += 1 @@ -376,7 +375,7 @@ def get( to_file: str = "mode_solver.hdf5", sim_file: str = "simulation.hdf5", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> ModeSolverTask: """Get mode solver task from the server by id. @@ -418,7 +417,7 @@ def get_info(self) -> ModeSolverTask: return ModeSolverTask(**resp, mode_solver=self.mode_solver) def upload( - self, verbose: bool = True, progress_callback: Callable[[float], None] = None + self, verbose: bool = True, progress_callback: Optional[Callable[[float], None]] = None ) -> None: """Upload this task's 'mode_solver' to the server. @@ -501,7 +500,7 @@ def get_modesolver( to_file: str = "mode_solver.hdf5", sim_file: str = "simulation.hdf5", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> ModeSolver: """Get mode solver associated with this task from the server. @@ -585,7 +584,7 @@ def get_result( self, to_file: str = "mode_solver_data.hdf5", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> ModeSolverData: """Get mode solver results for this task from the server. @@ -648,7 +647,7 @@ def get_log( self, to_file: str = "mode_solver.log", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> pathlib.Path: """Get execution log for this task from the server. diff --git a/tidy3d/web/api/tidy3d_stub.py b/tidy3d/web/api/tidy3d_stub.py index 5a5af337d1..c5a6c94228 100644 --- a/tidy3d/web/api/tidy3d_stub.py +++ b/tidy3d/web/api/tidy3d_stub.py @@ -3,35 +3,45 @@ from __future__ import annotations import json -from typing import Callable, List, Union +from typing import Callable, Optional, Union import pydantic.v1 as pd from pydantic.v1 import BaseModel -from tidy3d.components.tcad.data.sim_data import HeatChargeSimulationData, HeatSimulationData +from tidy3d import log +from tidy3d.components.base import _get_valid_extension +from tidy3d.components.data.monitor_data import ModeSolverData +from tidy3d.components.data.sim_data import SimulationData +from tidy3d.components.eme.data.sim_data import EMESimulationData +from tidy3d.components.eme.simulation import EMESimulation +from tidy3d.components.mode.data.sim_data import ModeSimulationData +from tidy3d.components.mode.simulation import ModeSimulation +from tidy3d.components.simulation import Simulation +from tidy3d.components.tcad.data.sim_data import ( + HeatChargeSimulationData, + HeatSimulationData, + VolumeMesherData, +) +from tidy3d.components.tcad.mesher import VolumeMesher from tidy3d.components.tcad.simulation.heat import HeatSimulation from tidy3d.components.tcad.simulation.heat_charge import HeatChargeSimulation - -from ... import log -from ...components.base import _get_valid_extension -from ...components.data.monitor_data import ModeSolverData -from ...components.data.sim_data import SimulationData -from ...components.eme.data.sim_data import EMESimulationData -from ...components.eme.simulation import EMESimulation -from ...components.mode.data.sim_data import ModeSimulationData -from ...components.mode.simulation import ModeSimulation -from ...components.simulation import Simulation -from ...plugins.mode.mode_solver import ModeSolver -from ..core.file_util import ( +from tidy3d.plugins.mode.mode_solver import ModeSolver +from tidy3d.web.core.file_util import ( read_simulation_from_hdf5, read_simulation_from_hdf5_gz, read_simulation_from_json, ) -from ..core.stub import TaskStub, TaskStubData -from ..core.types import TaskType +from tidy3d.web.core.stub import TaskStub, TaskStubData +from tidy3d.web.core.types import TaskType SimulationType = Union[ - Simulation, HeatChargeSimulation, HeatSimulation, EMESimulation, ModeSolver, ModeSimulation + Simulation, + HeatChargeSimulation, + HeatSimulation, + EMESimulation, + ModeSolver, + ModeSimulation, + VolumeMesher, ] SimulationDataType = Union[ SimulationData, @@ -76,18 +86,20 @@ def from_file(cls, file_path: str) -> SimulationType: data = json.loads(json_str) type_ = data["type"] - if "Simulation" == type_: + if type_ == "Simulation": sim = Simulation.from_file(file_path) - elif "ModeSolver" == type_: + elif type_ == "ModeSolver": sim = ModeSolver.from_file(file_path) - elif "HeatSimulation" == type_: + elif type_ == "HeatSimulation": sim = HeatSimulation.from_file(file_path) - elif "HeatChargeSimulation" == type_: + elif type_ == "HeatChargeSimulation": sim = HeatChargeSimulation.from_file(file_path) - elif "EMESimulation" == type_: + elif type_ == "EMESimulation": sim = EMESimulation.from_file(file_path) - elif "ModeSimulation" == type_: + elif type_ == "ModeSimulation": sim = ModeSimulation.from_file(file_path) + elif type_ == "VolumeMesher": + sim = VolumeMesher.from_file(file_path) return sim @@ -109,7 +121,7 @@ def to_file( """ self.simulation.to_file(file_path) - def to_hdf5_gz(self, fname: str, custom_encoders: List[Callable] = None) -> None: + def to_hdf5_gz(self, fname: str, custom_encoders: Optional[list[Callable]] = None) -> None: """Exports Union[:class:`.Simulation`, :class:`.HeatSimulation`, :class:`.EMESimulation`] instance to .hdf5.gz file. Parameters @@ -138,16 +150,18 @@ def get_type(self) -> str: """ if isinstance(self.simulation, Simulation): return TaskType.FDTD.name - elif isinstance(self.simulation, ModeSolver): + if isinstance(self.simulation, ModeSolver): return TaskType.MODE_SOLVER.name - elif isinstance(self.simulation, HeatSimulation): + if isinstance(self.simulation, HeatSimulation): return TaskType.HEAT.name - elif isinstance(self.simulation, HeatChargeSimulation): + if isinstance(self.simulation, HeatChargeSimulation): return TaskType.HEAT_CHARGE.name - elif isinstance(self.simulation, EMESimulation): + if isinstance(self.simulation, EMESimulation): return TaskType.EME.name - elif isinstance(self.simulation, ModeSimulation): + if isinstance(self.simulation, ModeSimulation): return TaskType.MODE.name + elif isinstance(self.simulation, VolumeMesher): + return TaskType.VOLUME_MESH.name def validate_pre_upload(self, source_required) -> None: """Perform some pre-checks on instances of component""" @@ -188,18 +202,20 @@ def from_file(cls, file_path: str) -> SimulationDataType: data = json.loads(json_str) type_ = data["type"] - if "SimulationData" == type_: + if type_ == "SimulationData": sim_data = SimulationData.from_file(file_path) - elif "ModeSolverData" == type_: + elif type_ == "ModeSolverData": sim_data = ModeSolverData.from_file(file_path) - elif "HeatSimulationData" == type_: + elif type_ == "HeatSimulationData": sim_data = HeatSimulationData.from_file(file_path) - elif "HeatChargeSimulationData" == type_: + elif type_ == "HeatChargeSimulationData": sim_data = HeatChargeSimulationData.from_file(file_path) - elif "EMESimulationData" == type_: + elif type_ == "EMESimulationData": sim_data = EMESimulationData.from_file(file_path) - elif "ModeSimulationData" == type_: + elif type_ == "ModeSimulationData": sim_data = ModeSimulationData.from_file(file_path) + elif type_ == "VolumeMesherData": + sim_data = VolumeMesherData.from_file(file_path) return sim_data diff --git a/tidy3d/web/api/webapi.py b/tidy3d/web/api/webapi.py index d0d42c7663..1302d23f82 100644 --- a/tidy3d/web/api/webapi.py +++ b/tidy3d/web/api/webapi.py @@ -1,24 +1,23 @@ """Provides lowest level, user-facing interface to server.""" +from __future__ import annotations + import json import os import tempfile import time -from datetime import datetime, timedelta -from typing import Callable, Dict, List, Union +from typing import Callable, Literal, Optional, Union -import pytz from requests import HTTPError from rich.progress import Progress -from ...components.medium import AbstractCustomMedium -from ...components.mode.mode_solver import ModeSolver -from ...components.mode.simulation import ModeSimulation -from ...components.types import Literal -from ...exceptions import WebError -from ...log import get_logging_console, log -from ..core.account import Account -from ..core.constants import ( +from tidy3d.components.medium import AbstractCustomMedium +from tidy3d.components.mode.mode_solver import ModeSolver +from tidy3d.components.mode.simulation import ModeSimulation +from tidy3d.exceptions import WebError +from tidy3d.log import get_logging_console, log +from tidy3d.web.core.account import Account +from tidy3d.web.core.constants import ( MODE_DATA_HDF5_GZ, MODE_FILE_HDF5_GZ, SIM_FILE_HDF5, @@ -26,16 +25,12 @@ SIMULATION_DATA_HDF5_GZ, TaskId, ) -from ..core.environment import Env -from ..core.task_core import Folder, SimulationTask -from ..core.task_info import ChargeType, TaskInfo -from ..core.types import PayType -from .connect_util import ( - REFRESH_TIME, - get_grid_points_str, - get_time_steps_str, - wait_for_connection, -) +from tidy3d.web.core.environment import Env +from tidy3d.web.core.task_core import Folder, SimulationTask +from tidy3d.web.core.task_info import ChargeType, TaskInfo +from tidy3d.web.core.types import PayType + +from .connect_util import REFRESH_TIME, get_grid_points_str, get_time_steps_str, wait_for_connection from .tidy3d_stub import SimulationDataType, SimulationType, Tidy3dStub, Tidy3dStubData # time between checking run status @@ -48,7 +43,7 @@ GUI_SUPPORTED_TASK_TYPES = ["FDTD", "MODE_SOLVER", "HEAT"] # if a solver is in beta stage, cost is subject to change -BETA_TASK_TYPES = ["HEAT", "EME", "HEAT_CHARGE"] +BETA_TASK_TYPES = ["HEAT", "EME", "HEAT_CHARGE", "VOLUME_MESH"] # map task_type to solver name for display SOLVER_NAME = { @@ -58,6 +53,7 @@ "EME": "EME", "HEAT": "Heat", "HEAT_CHARGE": "HeatCharge", + "VOLUME_MESH": "VolumeMesher", } @@ -77,16 +73,17 @@ def run( task_name: str, folder_name: str = "default", path: str = "simulation_data.hdf5", - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, - progress_callback_upload: Callable[[float], None] = None, - progress_callback_download: Callable[[float], None] = None, - solver_version: str = None, - worker_group: str = None, + progress_callback_upload: Optional[Callable[[float], None]] = None, + progress_callback_download: Optional[Callable[[float], None]] = None, + solver_version: Optional[str] = None, + worker_group: Optional[str] = None, simulation_type: str = "tidy3d", - parent_tasks: list[str] = None, + parent_tasks: Optional[list[str]] = None, reduce_simulation: Literal["auto", True, False] = "auto", pay_type: Union[PayType, str] = PayType.AUTO, + priority: Optional[int] = None, ) -> SimulationDataType: """ Submits a :class:`.Simulation` to server, starts running, monitors progress, downloads, @@ -121,7 +118,8 @@ def run( Whether to reduce structures in the simulation to the simulation domain only. Note: currently only implemented for the mode solver. pay_type: Union[PayType, str] = PayType.AUTO Which method to pay the simulation. - + priority: int = None + Task priority for vGPU queue (1=lowest, 10=highest). Returns ------- Union[:class:`.SimulationData`, :class:`.HeatSimulationData`, :class:`.EMESimulationData`] @@ -183,6 +181,7 @@ def run( solver_version=solver_version, worker_group=worker_group, pay_type=pay_type, + priority=priority, ) monitor(task_id, verbose=verbose) data = load( @@ -198,13 +197,13 @@ def upload( simulation: SimulationType, task_name: str, folder_name: str = "default", - callback_url: str = None, + callback_url: Optional[str] = None, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, simulation_type: str = "tidy3d", - parent_tasks: List[str] = None, + parent_tasks: Optional[list[str]] = None, source_required: bool = True, - solver_version: str = None, + solver_version: Optional[str] = None, reduce_simulation: Literal["auto", True, False] = "auto", ) -> TaskId: """ @@ -255,6 +254,9 @@ def upload( """ + if isinstance(simulation, (ModeSolver, ModeSimulation)): + simulation = get_reduced_simulation(simulation, reduce_simulation) + stub = Tidy3dStub(simulation=simulation) stub.validate_pre_upload(source_required=source_required) log.debug("Creating task.") @@ -284,8 +286,6 @@ def upload( remote_sim_file = SIM_FILE_HDF5_GZ if task_type == "MODE_SOLVER": remote_sim_file = MODE_FILE_HDF5_GZ - if task_type == "MODE_SOLVER" or task_type == "MODE": - simulation = get_reduced_simulation(simulation, reduce_simulation) task.upload_simulation( stub=stub, @@ -295,6 +295,8 @@ def upload( ) estimate_cost(task_id=task.task_id, solver_version=solver_version, verbose=verbose) + task.validate_post_upload(parent_tasks=parent_tasks) + # log the url for the task in the web UI log.debug(f"{Env.current.website_endpoint}/folders/{task.folder_id}/tasks/{task.task_id}") return task.task_id @@ -327,7 +329,6 @@ def get_reduced_simulation(simulation, reduce_simulation): there. Note that if we do the latter we may want to also modify the warning below to only happen if there are custom media *and* they extend beyond the simulation domain. """ - if reduce_simulation == "auto": if isinstance(simulation, ModeSimulation): sim_mediums = simulation.scene.mediums @@ -344,7 +345,6 @@ def get_reduced_simulation(simulation, reduce_simulation): " Setting 'reduce_simulation=True' will force simulation reduction in all cases and" " silence this warning." ) - if reduce_simulation: return simulation.reduced_simulation_copy return simulation @@ -374,9 +374,10 @@ def get_info(task_id: TaskId, verbose: bool = True) -> TaskInfo: @wait_for_connection def start( task_id: TaskId, - solver_version: str = None, - worker_group: str = None, + solver_version: Optional[str] = None, + worker_group: Optional[str] = None, pay_type: Union[PayType, str] = PayType.AUTO, + priority: Optional[int] = None, ) -> None: """Start running the simulation associated with task. @@ -391,10 +392,14 @@ def start( worker group pay_type: Union[PayType, str] = PayType.AUTO Which method to pay the simulation + priority: int = None + Task priority for vGPU queue (1=lowest, 10=highest). Note ---- To monitor progress, can call :meth:`monitor` after starting simulation. """ + if priority is not None and (priority < 1 or priority > 10): + raise ValueError("Priority must be between '1' and '10' if specified.") task = SimulationTask.get(task_id) if not task: raise ValueError("Task not found.") @@ -402,11 +407,12 @@ def start( solver_version=solver_version, worker_group=worker_group, pay_type=pay_type, + priority=priority, ) @wait_for_connection -def get_run_info(task_id: TaskId): +def get_run_info(task_id: TaskId) -> tuple[Optional[float], Optional[float]]: """Gets the % done and field_decay for a running task. Parameters @@ -594,14 +600,14 @@ def monitor_preprocess() -> None: else: while get_status(task_id) == "running": perc_done, _ = get_run_info(task_id) - time.sleep(1.0) + time.sleep(RUN_REFRESH_TIME) else: # non-verbose case, just keep checking until status is not running or perc_done >= 100 perc_done, _ = get_run_info(task_id) while perc_done is not None and perc_done < 100 and get_status(task_id) == "running": perc_done, field_decay = get_run_info(task_id) - time.sleep(1.0) + time.sleep(RUN_REFRESH_TIME) # post processing if verbose: @@ -630,7 +636,7 @@ def download( task_id: TaskId, path: str = "simulation_data.hdf5", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> None: """Download results of task to file. @@ -687,7 +693,7 @@ def download_hdf5( task_id: TaskId, path: str = SIM_FILE_HDF5, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> None: """Download the ``.hdf5`` file associated with the :class:`.Simulation` of a given task. @@ -747,7 +753,7 @@ def download_log( task_id: TaskId, path: str = "tidy3d.log", verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> None: """Download the tidy3d log file associated with a task. @@ -776,7 +782,7 @@ def load( path: str = "simulation_data.hdf5", replace_existing: bool = True, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> SimulationDataType: """ Download and Load simulation results into :class:`.SimulationData` object. @@ -867,19 +873,11 @@ def delete_old( folder = Folder.get(folder) if not folder: return 0 - tasks = folder.list_tasks() - if not tasks: - return 0 - tasks = list( - filter(lambda t: t.created_at < datetime.now(pytz.utc) - timedelta(days=days_old), tasks) - ) - for task in tasks: - task.delete() - return len(tasks) + return folder.delete_old(days_old) @wait_for_connection -def abort(task_id: TaskId): +def abort(task_id: TaskId) -> TaskInfo: """Abort server-side data associated with task. Parameters @@ -896,20 +894,19 @@ def abort(task_id: TaskId): task = SimulationTask.get(task_id) if not task: raise ValueError("Task not found.") - else: - task.abort() - console = get_logging_console() - url = _get_url(task.task_id) - console.log( - f"Task is aborting. View task using web UI at [link={url}]'{url}'[/link] to check the result." - ) - return TaskInfo(**{"taskId": task.task_id, **task.dict()}) + task.abort() + console = get_logging_console() + url = _get_url(task.task_id) + console.log( + f"Task is aborting. View task using web UI at [link={url}]'{url}'[/link] to check the result." + ) + return TaskInfo(**{"taskId": task.task_id, **task.dict()}) @wait_for_connection def get_tasks( - num_tasks: int = None, order: Literal["new", "old"] = "new", folder: str = "default" -) -> List[Dict]: + num_tasks: Optional[int] = None, order: Literal["new", "old"] = "new", folder: str = "default" +) -> list[dict]: """Get a list with the metadata of the last ``num_tasks`` tasks. Parameters @@ -940,7 +937,9 @@ def get_tasks( @wait_for_connection -def estimate_cost(task_id: str, verbose: bool = True, solver_version: str = None) -> float: +def estimate_cost( + task_id: str, verbose: bool = True, solver_version: Optional[str] = None +) -> float: """Compute the maximum FlexCredit charge for a given task. Parameters @@ -1090,6 +1089,31 @@ def real_cost(task_id: str, verbose=True) -> float: @wait_for_connection def account(verbose=True) -> Account: + """Get account information including FlexCredit balance and usage limits. + + Parameters + ---------- + verbose : bool = True + If ``True``, prints account information including credit balance, expiration, + and free simulation counts. + + Returns + ------- + Account + Object containing account information such as credit balance, expiration dates, + and daily free simulation counts. + + Examples + -------- + Get account information: + + .. code-block:: python + + account_info = web.account() + # Displays: + # Current FlexCredit balance: 10.00 and expiration date: 2024-12-31 23:59:59. + # Remaining daily free simulations: 3. + """ account_info = Account.get() if verbose and account_info: console = get_logging_console() @@ -1122,8 +1146,28 @@ def account(verbose=True) -> Account: @wait_for_connection def test() -> None: - """ - Confirm whether Tidy3D authentication is configured. Raises exception if not. + """Confirm whether Tidy3D authentication is configured. + + Raises + ------ + WebError + If Tidy3D authentication is not configured correctly. + + Notes + ----- + This method tests the authentication configuration by attempting to retrieve + the task list. If authentication is not properly set up, it will raise an + exception with instructions on how to configure authentication. + + Examples + -------- + Test authentication: + + .. code-block:: python + + web.test() + # If successful, displays: + # Authentication configured successfully! """ try: # note, this is a little slow, but the only call that doesn't require providing a task id. diff --git a/tidy3d/web/cli/__init__.py b/tidy3d/web/cli/__init__.py index ada31566b2..bd3bf238d0 100644 --- a/tidy3d/web/cli/__init__.py +++ b/tidy3d/web/cli/__init__.py @@ -2,6 +2,8 @@ tidy3d command line tool. """ +from __future__ import annotations + from .app import tidy3d_cli __all__ = ["tidy3d_cli"] diff --git a/tidy3d/web/cli/app.py b/tidy3d/web/cli/app.py index ea16ad4e49..76a9572f09 100644 --- a/tidy3d/web/cli/app.py +++ b/tidy3d/web/cli/app.py @@ -2,6 +2,8 @@ Commandline interface for tidy3d. """ +from __future__ import annotations + import json import os.path import ssl @@ -10,10 +12,11 @@ import requests import toml -from ..cli.constants import CONFIG_FILE, CREDENTIAL_FILE, TIDY3D_DIR -from ..cli.migrate import migrate -from ..core.constants import HEADER_APIKEY, KEY_APIKEY -from ..core.environment import Env +from tidy3d.web.cli.constants import CONFIG_FILE, CREDENTIAL_FILE, TIDY3D_DIR +from tidy3d.web.cli.migrate import migrate +from tidy3d.web.core.constants import HEADER_APIKEY, KEY_APIKEY +from tidy3d.web.core.environment import Env + from .develop.index import develop # Prevent race condition on threads diff --git a/tidy3d/web/cli/constants.py b/tidy3d/web/cli/constants.py index d5ae0b78a3..60961f28fe 100644 --- a/tidy3d/web/cli/constants.py +++ b/tidy3d/web/cli/constants.py @@ -1,5 +1,7 @@ """Constants for the CLI.""" +from __future__ import annotations + import os from os.path import expanduser diff --git a/tidy3d/web/cli/develop/__init__.py b/tidy3d/web/cli/develop/__init__.py index 022b3049fa..98ef3b1300 100644 --- a/tidy3d/web/cli/develop/__init__.py +++ b/tidy3d/web/cli/develop/__init__.py @@ -1,4 +1,6 @@ # Import from documentation.py +from __future__ import annotations + from .documentation import ( build_documentation, # build_documentation_pdf, @@ -35,30 +37,30 @@ from .utils import echo_and_check_subprocess, echo_and_run_subprocess, get_install_directory __all__ = [ + "activate_correct_poetry_python", "benchmark_timing_operations", "benchmark_timing_operations_command", "build_documentation", # "build_documentation_pdf", "build_documentation_from_remote_notebooks", "commit", - # "convert_all_markdown_to_rst_command", - "replace_in_files_command", - "test_options", - "test_in_environment_command", - "activate_correct_poetry_python", "configure_submodules", - "verify_pandoc_is_installed_and_version_less_than_3", - "verify_pipx_is_installed", - "verify_poetry_is_installed", - "verify_sphinx_is_installed", + "develop", + "echo_and_check_subprocess", + "echo_and_run_subprocess", + "get_install_directory", "get_install_directory_command", "install_development_environment", "install_in_poetry", + # "convert_all_markdown_to_rst_command", + "replace_in_files_command", + "test_in_environment_command", + "test_options", "uninstall_development_environment", "update_submodules_remote", "verify_development_environment", - "get_install_directory", - "echo_and_run_subprocess", - "echo_and_check_subprocess", - "develop", + "verify_pandoc_is_installed_and_version_less_than_3", + "verify_pipx_is_installed", + "verify_poetry_is_installed", + "verify_sphinx_is_installed", ] diff --git a/tidy3d/web/cli/develop/documentation.py b/tidy3d/web/cli/develop/documentation.py index fc3fc9d5e8..9da6926577 100644 --- a/tidy3d/web/cli/develop/documentation.py +++ b/tidy3d/web/cli/develop/documentation.py @@ -13,6 +13,8 @@ poetry run tidy3d develop convert-all-markdown-to-rst """ +from __future__ import annotations + import json import os from typing import Optional diff --git a/tidy3d/web/cli/develop/index.py b/tidy3d/web/cli/develop/index.py index ac0af5f329..bbb63fef78 100644 --- a/tidy3d/web/cli/develop/index.py +++ b/tidy3d/web/cli/develop/index.py @@ -1,5 +1,7 @@ """Console script subcommand for tidy3d.""" +from __future__ import annotations + import click __all__ = [ @@ -15,4 +17,3 @@ def develop(): This command group includes several subcommands for various development tasks such as verifying and setting up the development environment, building documentation, testing, and more. """ - pass diff --git a/tidy3d/web/cli/develop/install.py b/tidy3d/web/cli/develop/install.py index 0a7ca6cc2e..302cc4ac55 100644 --- a/tidy3d/web/cli/develop/install.py +++ b/tidy3d/web/cli/develop/install.py @@ -4,6 +4,8 @@ are available as CLI commands when tidy3d is installed. """ +from __future__ import annotations + import platform import re import subprocess @@ -16,16 +18,16 @@ __all__ = [ "activate_correct_poetry_python", "configure_submodules", - "verify_pandoc_is_installed_and_version_less_than_3", - "verify_pipx_is_installed", - "verify_poetry_is_installed", - "verify_sphinx_is_installed", "get_install_directory_command", "install_development_environment", "install_in_poetry", "uninstall_development_environment", "update_submodules_remote", "verify_development_environment", + "verify_pandoc_is_installed_and_version_less_than_3", + "verify_pipx_is_installed", + "verify_poetry_is_installed", + "verify_sphinx_is_installed", ] @@ -33,9 +35,7 @@ def activate_correct_poetry_python(): """ Activate the correct Python environment for Poetry based on the operating system. """ - if platform.system() == "Windows": - echo_and_run_subprocess(["poetry", "env", "use", "python"]) - elif platform.system() == "Darwin": + if platform.system() == "Windows" or platform.system() == "Darwin": echo_and_run_subprocess(["poetry", "env", "use", "python"]) elif platform.system() == "Linux": try: @@ -87,12 +87,10 @@ def verify_pandoc_is_installed_and_version_less_than_3(): if major_version < 3: print(f"Pandoc is installed with version {version}, which is less than 3.") return True - else: - print(f"Pandoc version {version} is installed, but it is not less than 3.") - return False - else: - print("Pandoc version number could not be determined.") + print(f"Pandoc version {version} is installed, but it is not less than 3.") return False + print("Pandoc version number could not be determined.") + return False except subprocess.CalledProcessError: # This exception is raised if the command returned a non-zero exit status @@ -148,9 +146,9 @@ def verify_poetry_is_installed(): if result.returncode == 0: print("Poetry is installed: " + result.stdout) return True - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as exc: # This exception is raised if the command returned a non-zero exit status - raise OSError("Poetry is not installed or not found in the system PATH.") + raise OSError("Poetry is not installed or not found in the system PATH.") from exc def verify_sphinx_is_installed(): @@ -170,9 +168,9 @@ def verify_sphinx_is_installed(): ) # If the command was successful, we'll get the version info print("sphinx is installed: " + result.stdout) - except subprocess.CalledProcessError: + except subprocess.CalledProcessError as exc: # This exception is raised if the command returned a non-zero exit status - raise OSError("sphinx is not installed or not found in the poetry environment.") + raise OSError("sphinx is not installed or not found in the poetry environment.") from exc @develop.command(name="get-install-directory", help="Gets the TIDY3D base directory.") @@ -205,7 +203,7 @@ def install_development_environment(args=None): # Verify and install pipx if required try: verify_pipx_is_installed() - except: # NOQA: E722 + except Exception as exc: if platform.system() == "Windows": echo_and_check_subprocess(["scoop", "install", "pipx"]) echo_and_check_subprocess(["pipx", "ensurepath"]) @@ -219,15 +217,13 @@ def install_development_environment(args=None): raise OSError( "Unsupported operating system installation flow. Verify the subprocess commands in " "tidy3d develop are compatible with your operating system." - ) + ) from exc # Verify and install poetry if required try: verify_poetry_is_installed() - except: # NOQA: E722 - if platform.system() == "Windows": - echo_and_check_subprocess(["pipx", "install", "poetry"]) - elif platform.system() == "Darwin": + except Exception as exc: + if platform.system() == "Windows" or platform.system() == "Darwin": echo_and_check_subprocess(["pipx", "install", "poetry"]) elif platform.system() == "Linux": echo_and_check_subprocess(["python3", "-m", "pipx", "install", "poetry"]) @@ -235,16 +231,16 @@ def install_development_environment(args=None): raise OSError( "Unsupported operating system installation flow. Verify the subprocess commands in " "tidy3d develop are compatible with your operating system." - ) + ) from exc # Verify pandoc is installed try: verify_pandoc_is_installed_and_version_less_than_3() - except: # NOQA: E722 + except Exception as exc: raise OSError( "Please install pandoc < 3 depending on your platform: https://pandoc.org/installing.html . Then run this " "command again. You can also follow our detailed instructions under the development guide." - ) + ) from exc # Makes sure that poetry uses the python environment active on the terminal. @@ -328,7 +324,7 @@ def uninstall_development_environment(args=None): "Unsupported operating system installation flow. Verify the subprocess commands in " "tidy3d develop are compatible with your operating system." ) - else: # NOQA: E722 + else: print("poetry is not found on the PATH. It is already uninstalled from PATH.") # Verify and install pipx if required @@ -357,8 +353,7 @@ def uninstall_development_environment(args=None): "Please uninstall pandoc < 3 depending on your platform: https://pandoc.org/installing.html . Then run this " "command again. You can also follow our detailed instructions under the development guide." ) - else: # NOQA: E722 - print("pandoc is not found on the PATH. It is already uninstalled from PATH.") + print("pandoc is not found on the PATH. It is already uninstalled from PATH.") return 0 diff --git a/tidy3d/web/cli/develop/packaging.py b/tidy3d/web/cli/develop/packaging.py index 48e18f51c7..0b92790dfb 100644 --- a/tidy3d/web/cli/develop/packaging.py +++ b/tidy3d/web/cli/develop/packaging.py @@ -6,6 +6,8 @@ functionality to extract the timing performance of that specific operation and compare it to previous usages. """ +from __future__ import annotations + import pathlib import subprocess from pathlib import Path @@ -47,7 +49,7 @@ def benchmark_timing_operations( operations in the `tests` section and benchmark them properly using this. This function does not require poetry and can be run anywhere where a tidy3d installation is already implemented. The output file has an extension. """ - timing_command_list = list() + timing_command_list = [] if output_file is None: output_file = timing_command.split("_")[1:] + ".log" @@ -60,7 +62,7 @@ def benchmark_timing_operations( "The output file path " + str(output_file_path) + " does not exist and cannot be created." - ) + ) from None if in_poetry_environment: timing_command_list += ["poetry", "run"] @@ -70,9 +72,9 @@ def benchmark_timing_operations( except KeyError: # This has to do with choosing a timing command not available in the dictionary raise KeyError( - f"Make sure the selected timing command {timing_command}" - + "corresponds to an existing command." - ) + f"Make sure the selected timing command {timing_command} " + "corresponds to an existing command." + ) from None echo_and_check_subprocess( command=timing_command_list, stdout=output_file_write, stderr=subprocess.STDOUT @@ -90,7 +92,7 @@ def benchmark_timing_operations( default=True, type=bool, is_flag=True, - help="Runs in poetry environment if " "True.", + help="Runs in poetry environment if True.", ) @click.option( "-o", diff --git a/tidy3d/web/cli/develop/tests.py b/tidy3d/web/cli/develop/tests.py index 4022643882..3a75a07389 100644 --- a/tidy3d/web/cli/develop/tests.py +++ b/tidy3d/web/cli/develop/tests.py @@ -3,6 +3,8 @@ notebooks in order to achieve reproducibility between hardwares. """ +from __future__ import annotations + import click from .index import develop @@ -10,8 +12,8 @@ from .utils import echo_and_run_subprocess __all__ = [ - "test_options", "test_in_environment_command", + "test_options", ] diff --git a/tidy3d/web/cli/develop/utils.py b/tidy3d/web/cli/develop/utils.py index c826c13a49..8faaf5d6e1 100644 --- a/tidy3d/web/cli/develop/utils.py +++ b/tidy3d/web/cli/develop/utils.py @@ -2,15 +2,17 @@ Utility functions for the tidy3d develop CLI. """ +from __future__ import annotations + import pathlib import subprocess import tidy3d __all__ = [ - "get_install_directory", - "echo_and_run_subprocess", "echo_and_check_subprocess", + "echo_and_run_subprocess", + "get_install_directory", ] diff --git a/tidy3d/web/cli/migrate.py b/tidy3d/web/cli/migrate.py index 48a00870da..17fbd3c7ed 100644 --- a/tidy3d/web/cli/migrate.py +++ b/tidy3d/web/cli/migrate.py @@ -1,5 +1,7 @@ """Migrate authentication to API key.""" +from __future__ import annotations + import json import os @@ -7,8 +9,9 @@ import requests import toml -from ..core.constants import HEADER_APPLICATION, HEADER_APPLICATION_VALUE, KEY_APIKEY -from ..core.environment import Env +from tidy3d.web.core.constants import HEADER_APPLICATION, HEADER_APPLICATION_VALUE, KEY_APIKEY +from tidy3d.web.core.environment import Env + from .constants import CONFIG_FILE, CREDENTIAL_FILE, TIDY3D_DIR @@ -41,35 +44,29 @@ def migrate() -> bool: if resp.status_code != 200: click.echo(f"Migrate to api key failed: {resp.text}") return False - else: - # click.echo(json.dumps(resp.json(), indent=4)) - access_token = resp.json()["data"]["auth"]["accessToken"] - headers["Authorization"] = f"Bearer {access_token}" - resp = requests.get(f"{Env.current.web_api_endpoint}/apikey", headers=headers) + # click.echo(json.dumps(resp.json(), indent=4)) + access_token = resp.json()["data"]["auth"]["accessToken"] + headers["Authorization"] = f"Bearer {access_token}" + resp = requests.get(f"{Env.current.web_api_endpoint}/apikey", headers=headers) + if resp.status_code != 200: + click.echo(f"Migrate to api key failed: {resp.text}") + return False + click.echo(json.dumps(resp.json(), indent=4)) + apikey = resp.json()["data"] + if not apikey: + resp = requests.post(f"{Env.current.web_api_endpoint}/apikey", headers=headers) if resp.status_code != 200: click.echo(f"Migrate to api key failed: {resp.text}") return False - else: - click.echo(json.dumps(resp.json(), indent=4)) - apikey = resp.json()["data"] - if not apikey: - resp = requests.post( - f"{Env.current.web_api_endpoint}/apikey", headers=headers - ) - if resp.status_code != 200: - click.echo(f"Migrate to api key failed: {resp.text}") - return False - else: - apikey = resp.json()["data"] - if not os.path.exists(TIDY3D_DIR): - os.mkdir(TIDY3D_DIR) - with open(CONFIG_FILE, "w+", encoding="utf-8") as config_file: - toml_config = toml.loads(config_file.read()) - toml_config.update({KEY_APIKEY: apikey}) - config_file.write(toml.dumps(toml_config)) + apikey = resp.json()["data"] + if not os.path.exists(TIDY3D_DIR): + os.mkdir(TIDY3D_DIR) + with open(CONFIG_FILE, "w+", encoding="utf-8") as config_file: + toml_config = toml.loads(config_file.read()) + toml_config.update({KEY_APIKEY: apikey}) + config_file.write(toml.dumps(toml_config)) - # rename auth.json to auth.json.bak - os.rename(CREDENTIAL_FILE, CREDENTIAL_FILE + ".bak") - return True - else: - click.echo("You can migrate to api key by running 'tidy3d migrate' command.") + # rename auth.json to auth.json.bak + os.rename(CREDENTIAL_FILE, CREDENTIAL_FILE + ".bak") + return True + click.echo("You can migrate to api key by running 'tidy3d migrate' command.") diff --git a/tidy3d/web/core/account.py b/tidy3d/web/core/account.py index c505b66487..07cef4caaa 100644 --- a/tidy3d/web/core/account.py +++ b/tidy3d/web/core/account.py @@ -63,5 +63,4 @@ def get(cls): if resp: account = Account(**resp) return account - else: - return None + return None diff --git a/tidy3d/web/core/cache.py b/tidy3d/web/core/cache.py index 87d55bd752..d83421ca21 100644 --- a/tidy3d/web/core/cache.py +++ b/tidy3d/web/core/cache.py @@ -1,4 +1,6 @@ """Local caches.""" +from __future__ import annotations + FOLDER_CACHE = {} S3_STS_TOKENS = {} diff --git a/tidy3d/web/core/constants.py b/tidy3d/web/core/constants.py index edadf62445..108d148800 100644 --- a/tidy3d/web/core/constants.py +++ b/tidy3d/web/core/constants.py @@ -1,6 +1,8 @@ """Defines constants for core.""" # HTTP Header key and value +from __future__ import annotations + HEADER_APIKEY = "simcloud-api-key" HEADER_VERSION = "tidy3d-python-version" HEADER_SOURCE = "source" diff --git a/tidy3d/web/core/core_config.py b/tidy3d/web/core/core_config.py index 4ab8ed41a8..77f0fb5c33 100644 --- a/tidy3d/web/core/core_config.py +++ b/tidy3d/web/core/core_config.py @@ -1,5 +1,7 @@ """Tidy3d core log, need init config from Tidy3d api""" +from __future__ import annotations + import logging as log # default setting diff --git a/tidy3d/web/core/environment.py b/tidy3d/web/core/environment.py index d7aa016f53..261f53ea93 100644 --- a/tidy3d/web/core/environment.py +++ b/tidy3d/web/core/environment.py @@ -1,7 +1,10 @@ """Environment Setup.""" +from __future__ import annotations + import os import ssl +from typing import Optional from pydantic.v1 import BaseSettings, Field @@ -12,15 +15,16 @@ class EnvironmentConfig(BaseSettings): """Basic Configuration for definition environment.""" def __hash__(self): - return hash((type(self),) + tuple(self.__dict__.values())) + return hash((type(self), *tuple(self.__dict__.values()))) name: str web_api_endpoint: str website_endpoint: str s3_region: str ssl_verify: bool = Field(True, env="TIDY3D_SSL_VERIFY") - enable_caching: bool = None - ssl_version: ssl.TLSVersion = None + enable_caching: Optional[bool] = None + ssl_version: Optional[ssl.TLSVersion] = None + env_vars: Optional[dict[str, str]] = None def active(self) -> None: """Activate the environment instance.""" @@ -71,6 +75,17 @@ def get_real_url(self, path: str) -> str: ) +nexus = EnvironmentConfig( + name="nexus", + web_api_endpoint="http://127.0.0.1:5000", + ssl_verify=False, + enable_caching=False, + s3_region="us-east-1", + website_endpoint="http://127.0.0.1/tidy3d", + env_vars={"AWS_ENDPOINT_URL_S3": "http://127.0.0.1:9000"}, +) + + class Environment: """Environment decorator for user interactive. @@ -82,15 +97,17 @@ class Environment: ... """ - env_map = dict( - dev=dev, - uat=uat, - prod=prod, - ) + env_map = { + "dev": dev, + "uat": uat, + "prod": prod, + "nexus": nexus, + } def __init__(self): log = get_logger() """Initialize the environment.""" + self._previous_env_vars = {} env_key = os.environ.get("TIDY3D_ENV") env_key = env_key.lower() if env_key else env_key log.info(f"env_key is {env_key}") @@ -105,6 +122,11 @@ def __init__(self): ) self._current = prod + if self._current.env_vars: + for key, value in self._current.env_vars.items(): + self._previous_env_vars[key] = os.environ.get(key) + os.environ[key] = value + @property def current(self) -> EnvironmentConfig: """Get the current environment. @@ -160,6 +182,17 @@ def prod(self) -> EnvironmentConfig: """ return prod + @property + def nexus(self) -> EnvironmentConfig: + """Get the nexus environment. + + Returns + ------- + EnvironmentConfig + The config for the nexus environment. + """ + return nexus + def set_current(self, config: EnvironmentConfig) -> None: """Set the current environment. @@ -168,6 +201,19 @@ def set_current(self, config: EnvironmentConfig) -> None: config : EnvironmentConfig The environment to set to current. """ + for key, value in self._previous_env_vars.items(): + if value is None: + if key in os.environ: + del os.environ[key] + else: + os.environ[key] = value + self._previous_env_vars = {} + + if config.env_vars: + for key, value in config.env_vars.items(): + self._previous_env_vars[key] = os.environ.get(key) + os.environ[key] = value + self._current = config def enable_caching(self, enable_caching: bool = True) -> None: diff --git a/tidy3d/web/core/exceptions.py b/tidy3d/web/core/exceptions.py index 398550eca1..4061a8c6f8 100644 --- a/tidy3d/web/core/exceptions.py +++ b/tidy3d/web/core/exceptions.py @@ -1,12 +1,16 @@ """Custom Tidy3D exceptions""" +from __future__ import annotations + +from typing import Optional + from .core_config import get_logger class WebError(Exception): """Any error in tidy3d""" - def __init__(self, message: str = None): + def __init__(self, message: Optional[str] = None): """Log just the error message and then raise the Exception.""" log = get_logger() super().__init__(message) @@ -15,5 +19,3 @@ def __init__(self, message: str = None): class WebNotFoundError(WebError): """A generic error indicating an HTTP 404 (resource not found).""" - - pass diff --git a/tidy3d/web/core/file_util.py b/tidy3d/web/core/file_util.py index 9305eaab1d..833e1e1f71 100644 --- a/tidy3d/web/core/file_util.py +++ b/tidy3d/web/core/file_util.py @@ -1,5 +1,7 @@ """File compression utilities""" +from __future__ import annotations + import gzip import os import shutil @@ -7,7 +9,7 @@ import h5py -from ..core.constants import JSON_TAG +from tidy3d.web.core.constants import JSON_TAG def compress_file_to_gzip(input_file, output_gz_file): diff --git a/tidy3d/web/core/http_util.py b/tidy3d/web/core/http_util.py index 1535959465..ca8c00abc3 100644 --- a/tidy3d/web/core/http_util.py +++ b/tidy3d/web/core/http_util.py @@ -1,10 +1,11 @@ """Http connection pool and authentication management.""" +from __future__ import annotations + import os from enum import Enum from functools import wraps from os.path import expanduser -from typing import Dict import requests import toml @@ -104,7 +105,7 @@ def api_key_auth(request: requests.request) -> requests.request: return request -def get_headers() -> Dict[str, str]: +def get_headers() -> dict[str, str]: """get headers for http request. Returns @@ -167,6 +168,7 @@ def __init__(self, session: requests.Session): ssl_version = Env.current.ssl_version if ssl_version: session.mount("https://", TLSAdapter()) + session.verify = Env.current.ssl_verify self.session = session def reinit(self): @@ -176,6 +178,7 @@ def reinit(self): if ssl_version and not REINITIALIZED: self.session.mount("https://", TLSAdapter()) REINITIALIZED = True + self.session.verify = Env.current.ssl_verify @http_interceptor def get(self, path: str, json=None, params=None): diff --git a/tidy3d/web/core/s3utils.py b/tidy3d/web/core/s3utils.py index b687cc11d0..3df8b1bd70 100644 --- a/tidy3d/web/core/s3utils.py +++ b/tidy3d/web/core/s3utils.py @@ -1,12 +1,15 @@ """handles filesystem, storage""" +from __future__ import annotations + import os import pathlib import tempfile import urllib +from collections.abc import Mapping from datetime import datetime from enum import Enum -from typing import Callable, Mapping +from typing import Callable, Optional import boto3 from boto3.s3.transfer import TransferConfig @@ -26,6 +29,8 @@ from .file_util import extract_gzip_file from .http_util import http +IN_TRANSIT_SUFFIX = ".tmp" + class _UserCredential(BaseModel): """Stores information about user credentials.""" @@ -179,7 +184,7 @@ def _get_progress(action: _S3Action): def get_s3_sts_token( - resource_id: str, file_name: str, extra_arguments: Mapping[str, str] = None + resource_id: str, file_name: str, extra_arguments: Optional[Mapping[str, str]] = None ) -> _S3STSToken: """Get s3 sts token for the given resource id and file name. @@ -213,8 +218,8 @@ def upload_file( path: str, remote_filename: str, verbose: bool = True, - progress_callback: Callable[[float], None] = None, - extra_arguments: Mapping[str, str] = None, + progress_callback: Optional[Callable[[float], None]] = None, + extra_arguments: Optional[Mapping[str, str]] = None, ): """Upload a file to S3. @@ -279,9 +284,9 @@ def _callback(bytes_in_chunk): def download_file( resource_id: str, remote_filename: str, - to_file: str = None, + to_file: Optional[str] = None, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> pathlib.Path: """Download file from S3. @@ -309,12 +314,12 @@ def download_file( # set to_file if None if not to_file: path = pathlib.Path(resource_id) - to_file = path / remote_basename + to_path = path / remote_basename else: - to_file = pathlib.Path(to_file) + to_path = pathlib.Path(to_file) - # make the leading directories in the 'to_file', if any - to_file.parent.mkdir(parents=True, exist_ok=True) + # make the leading directories in the 'to_path', if any + to_path.parent.mkdir(parents=True, exist_ok=True) def _download(_callback: Callable) -> None: """Perform the download with a callback function. @@ -324,14 +329,25 @@ def _download(_callback: Callable) -> None: _callback : Callable[[float], None] Callback function for download, accepts ``bytes_in_chunk`` """ - - client.download_file( - Bucket=token.get_bucket(), - Filename=str(to_file), - Key=token.get_s3_key(), - Callback=_callback, - Config=_s3_config, - ) + # Caller can assume the existence of the file means download succeeded. + # So make sure this file does not exist until that assumption is true. + to_path.unlink(missing_ok=True) + # Download to a temporary file. + try: + fd, tmp_file_path_str = tempfile.mkstemp(suffix=IN_TRANSIT_SUFFIX, dir=to_path.parent) + os.close(fd) # `tempfile.mkstemp()` creates and opens a randomly named file. close it. + to_path_tmp = pathlib.Path(tmp_file_path_str) + client.download_file( + Bucket=token.get_bucket(), + Filename=tmp_file_path_str, + Key=token.get_s3_key(), + Callback=_callback, + Config=_s3_config, + ) + to_path_tmp.rename(to_file) + except Exception as e: + to_path_tmp.unlink(missing_ok=True) # Delete incompletely downloaded file. + raise e if progress_callback is not None: _download(progress_callback) @@ -352,15 +368,15 @@ def _callback(bytes_in_chunk): else: _download(lambda bytes_in_chunk: None) - return to_file + return to_path def download_gz_file( resource_id: str, remote_filename: str, - to_file: str = None, + to_file: Optional[str] = None, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> pathlib.Path: """Download a ``.gz`` file and unzip it into ``to_file``, unless ``to_file`` itself ends in .gz @@ -391,24 +407,24 @@ def download_gz_file( # Otherwise, download and unzip # The tempfile is set as ``hdf5.gz`` so that the mock download in the webapi tests works - tmp_file, tmp_file_path = tempfile.mkstemp(".hdf5.gz") + tmp_file, tmp_file_path_str = tempfile.mkstemp(".hdf5.gz") os.close(tmp_file) # make the leading directories in the 'to_file', if any - to_file = pathlib.Path(to_file) - to_file.parent.mkdir(parents=True, exist_ok=True) + to_path = pathlib.Path(to_file) + to_path.parent.mkdir(parents=True, exist_ok=True) try: download_file( resource_id, remote_filename, - to_file=tmp_file_path, + to_file=tmp_file_path_str, verbose=verbose, progress_callback=progress_callback, ) - if os.path.exists(tmp_file_path): - extract_gzip_file(tmp_file_path, to_file) + if os.path.exists(tmp_file_path_str): + extract_gzip_file(tmp_file_path_str, to_path) else: raise WebError(f"Failed to download and extract '{remote_filename}'.") finally: - os.unlink(tmp_file_path) - return to_file + os.unlink(tmp_file_path_str) + return to_path diff --git a/tidy3d/web/core/stub.py b/tidy3d/web/core/stub.py index 9b4c5fd4a2..153fd69f22 100644 --- a/tidy3d/web/core/stub.py +++ b/tidy3d/web/core/stub.py @@ -21,7 +21,6 @@ def from_file(self, file_path) -> TaskStubData: An instance of the component class calling ``load``. """ - pass @abstractmethod def to_file(self, file_path): @@ -37,7 +36,6 @@ def to_file(self, file_path): :class:`Stub` An instance of the component class calling ``load``. """ - pass class TaskStub(ABC): @@ -55,7 +53,6 @@ def from_file(self, file_path) -> TaskStub: :class:`TaskStubData` An instance of the component class calling ``load``. """ - pass @abstractmethod def to_file(self, file_path): @@ -71,7 +68,6 @@ def to_file(self, file_path): :class:`Stub` An instance of the component class calling ``load``. """ - pass @abstractmethod def to_hdf5_gz(self, fname: str) -> None: @@ -82,4 +78,3 @@ def to_hdf5_gz(self, fname: str) -> None: fname : str Full path to the .hdf5.gz file to save the :class:`TaskStub` to. """ - pass diff --git a/tidy3d/web/core/task_core.py b/tidy3d/web/core/task_core.py index 3447369c19..376aef301b 100644 --- a/tidy3d/web/core/task_core.py +++ b/tidy3d/web/core/task_core.py @@ -6,13 +6,14 @@ import pathlib import tempfile from datetime import datetime -from typing import Callable, List, Optional, Tuple, Union +from typing import Callable, Optional, Union import pydantic.v1 as pd from botocore.exceptions import ClientError from pydantic.v1 import Extra, Field, parse_obj_as import tidy3d as td +from tidy3d.exceptions import ValidationError from . import http_util from .cache import FOLDER_CACHE @@ -47,7 +48,7 @@ def list(cls) -> []: resp = http.get("tidy3d/projects") return ( parse_obj_as( - List[Folder], + list[Folder], resp, ) if resp @@ -101,7 +102,15 @@ def delete(self): http.delete(f"tidy3d/projects/{self.folder_id}") - def list_tasks(self) -> List[Tidy3DResource]: + def delete_old(self, days_old: int) -> int: + """Remove folder contents older than ``days_old``.""" + + return http.delete( + f"tidy3d/tasks/{self.folder_id}/tasks", + params={"daysOld": days_old}, + ) + + def list_tasks(self) -> list[Tidy3DResource]: """List all tasks in this folder. Returns @@ -112,7 +121,7 @@ def list_tasks(self) -> List[Tidy3DResource]: resp = http.get(f"tidy3d/projects/{self.folder_id}/tasks") return ( parse_obj_as( - List[SimulationTask], + list[SimulationTask], resp, ) if resp @@ -196,9 +205,9 @@ def create( task_type: str, task_name: str, folder_name: str = "default", - callback_url: str = None, + callback_url: Optional[str] = None, simulation_type: str = "tidy3d", - parent_tasks: List[str] = None, + parent_tasks: Optional[list[str]] = None, file_type: str = "Gz", ) -> SimulationTask: """Create a new task on the server. @@ -273,7 +282,7 @@ def get(cls, task_id: str, verbose: bool = True) -> SimulationTask: return task @classmethod - def get_running_tasks(cls) -> List[SimulationTask]: + def get_running_tasks(cls) -> list[SimulationTask]: """Get a list of running tasks from the server" Returns @@ -285,7 +294,7 @@ def get_running_tasks(cls) -> List[SimulationTask]: resp = http.get("tidy3d/py/tasks") if not resp: return [] - return parse_obj_as(List[SimulationTask], resp) + return parse_obj_as(list[SimulationTask], resp) def delete(self, versions: bool = False): """Delete current task from server. @@ -349,7 +358,7 @@ def upload_simulation( self, stub: TaskStub, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, remote_sim_file: str = SIM_FILE_HDF5_GZ, ) -> None: """Upload :class:`.Simulation` object to Server. @@ -389,7 +398,7 @@ def upload_file( local_file: str, remote_filename: str, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, ) -> None: """ Upload file to platform. Using this method when the json file is too large to parse @@ -418,9 +427,10 @@ def upload_file( def submit( self, - solver_version: str = None, - worker_group: str = None, + solver_version: Optional[str] = None, + worker_group: Optional[str] = None, pay_type: Union[PayType, str] = PayType.AUTO, + priority: Optional[int] = None, ): """Kick off this task. @@ -436,6 +446,8 @@ def submit( worker group pay_type: Union[PayType, str] = PayType.AUTO Which method to pay the simulation. + priority: int = None + Task priority for vGPU queue (1=lowest, 10=highest). """ pay_type = PayType(pay_type) if not isinstance(pay_type, PayType) else pay_type @@ -452,6 +464,7 @@ def submit( "protocolVersion": protocol_version, "enableCaching": Env.current.enable_caching, "payType": pay_type.value, + "priority": priority, }, ) @@ -490,7 +503,7 @@ def get_sim_data_hdf5( self, to_file: str, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, remote_data_file: str = SIMULATION_DATA_HDF5_GZ, ) -> pathlib.Path: """Get simulation data file from Server. @@ -547,7 +560,7 @@ def get_simulation_hdf5( self, to_file: str, verbose: bool = True, - progress_callback: Callable[[float], None] = None, + progress_callback: Optional[Callable[[float], None]] = None, remote_sim_file: str = SIM_FILE_HDF5_GZ, ) -> pathlib.Path: """Get simulation.hdf5 file from Server. @@ -577,7 +590,7 @@ def get_simulation_hdf5( progress_callback=progress_callback, ) - def get_running_info(self) -> Tuple[float, float]: + def get_running_info(self) -> tuple[float, float]: """Gets the % done and field_decay for a running task. Returns @@ -598,7 +611,10 @@ def get_running_info(self) -> Tuple[float, float]: return perc_done, field_decay def get_log( - self, to_file: str, verbose: bool = True, progress_callback: Callable[[float], None] = None + self, + to_file: str, + verbose: bool = True, + progress_callback: Optional[Callable[[float], None]] = None, ) -> pathlib.Path: """Get log file from Server. @@ -660,3 +676,33 @@ def abort(self): return http.put( "tidy3d/tasks/abort", json={"taskType": self.task_type, "taskId": self.task_id} ) + + def validate_post_upload(self, parent_tasks: Optional[list[str]] = None): + """Perform checks after task is uploaded and metadata is processed.""" + if self.task_type == "HEAT_CHARGE" and parent_tasks: + try: + if len(parent_tasks) > 1: + raise ValueError( + "A single parent 'task_id' corresponding to the task in which the meshing " + "was run must be provided." + ) + try: + # get mesh task info + mesh_task = SimulationTask.get(parent_tasks[0], verbose=False) + assert mesh_task.task_type == "VOLUME_MESH" + assert mesh_task.status == "success" + # get up-to-date task info + task = SimulationTask.get(self.task_id, verbose=False) + if task.fileMd5 != mesh_task.childFileMd5: + raise ValidationError( + "Simulation stored in parent task 'VolumeMesher' does not match the " + "current simulation." + ) + except Exception as e: + raise ValidationError( + "The parent task must be a 'VolumeMesher' task which has been successfully " + "run and is associated to the same 'HeatChargeSimulation' as provided here." + ) from e + + except Exception as e: + raise WebError(f"Provided 'parent_tasks' failed validation: {e!s}") from e diff --git a/tidy3d/web/core/task_info.py b/tidy3d/web/core/task_info.py index f33093b392..3406c62b3a 100644 --- a/tidy3d/web/core/task_info.py +++ b/tidy3d/web/core/task_info.py @@ -1,5 +1,7 @@ """Defines information about a task""" +from __future__ import annotations + from abc import ABC from datetime import datetime from enum import Enum diff --git a/tidy3d/web/core/types.py b/tidy3d/web/core/types.py index 748cfc7a8a..2ecf066402 100644 --- a/tidy3d/web/core/types.py +++ b/tidy3d/web/core/types.py @@ -54,6 +54,7 @@ class TaskType(str, Enum): HEAT_CHARGE = "HEAT_CHARGE" EME = "EME" MODE = "MODE" + VOLUME_MESH = "VOLUME_MESH" class PayType(str, Enum): diff --git a/tidy3d/web/environment.py b/tidy3d/web/environment.py index 287abd3313..af4b089a96 100644 --- a/tidy3d/web/environment.py +++ b/tidy3d/web/environment.py @@ -1,5 +1,7 @@ """preserve from tidy3d.web.environment import Env backward compatibility""" +from __future__ import annotations + from .core.environment import Env __all__ = ["Env"]